OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 // | 4 // |
5 // This file contains the definitions of the installer functions that build | 5 // This file contains the definitions of the installer functions that build |
6 // the WorkItemList used to install the application. | 6 // the WorkItemList used to install the application. |
7 | 7 |
8 #include "chrome/installer/setup/install_worker.h" | 8 #include "chrome/installer/setup/install_worker.h" |
9 | 9 |
10 #include <oaidl.h> | 10 #include <oaidl.h> |
11 #include <shlobj.h> | 11 #include <shlobj.h> |
12 #include <time.h> | 12 #include <time.h> |
13 | 13 |
14 #include <algorithm> | |
14 #include <vector> | 15 #include <vector> |
15 | 16 |
16 #include "base/bind.h" | 17 #include "base/bind.h" |
17 #include "base/command_line.h" | 18 #include "base/command_line.h" |
18 #include "base/files/file_path.h" | 19 #include "base/files/file_path.h" |
19 #include "base/files/file_util.h" | 20 #include "base/files/file_util.h" |
20 #include "base/logging.h" | 21 #include "base/logging.h" |
21 #include "base/memory/scoped_ptr.h" | 22 #include "base/memory/scoped_ptr.h" |
22 #include "base/path_service.h" | 23 #include "base/path_service.h" |
24 #include "base/strings/string_tokenizer.h" | |
23 #include "base/strings/string_util.h" | 25 #include "base/strings/string_util.h" |
26 #include "base/strings/stringprintf.h" | |
24 #include "base/strings/utf_string_conversions.h" | 27 #include "base/strings/utf_string_conversions.h" |
25 #include "base/version.h" | 28 #include "base/version.h" |
26 #include "base/win/registry.h" | 29 #include "base/win/registry.h" |
27 #include "base/win/scoped_comptr.h" | 30 #include "base/win/scoped_comptr.h" |
28 #include "base/win/windows_version.h" | 31 #include "base/win/windows_version.h" |
29 #include "chrome/common/chrome_constants.h" | 32 #include "chrome/common/chrome_constants.h" |
30 #include "chrome/common/chrome_switches.h" | 33 #include "chrome/common/chrome_switches.h" |
31 #include "chrome/installer/setup/install.h" | 34 #include "chrome/installer/setup/install.h" |
32 #include "chrome/installer/setup/setup_constants.h" | 35 #include "chrome/installer/setup/setup_constants.h" |
33 #include "chrome/installer/setup/setup_util.h" | 36 #include "chrome/installer/setup/setup_util.h" |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
71 L"{6C288DD7-76FB-4721-B628-56FAC252E199}"; | 74 L"{6C288DD7-76FB-4721-B628-56FAC252E199}"; |
72 | 75 |
73 const wchar_t kElevationPolicyKeyPath[] = | 76 const wchar_t kElevationPolicyKeyPath[] = |
74 L"SOFTWARE\\Microsoft\\Internet Explorer\\Low Rights\\ElevationPolicy\\"; | 77 L"SOFTWARE\\Microsoft\\Internet Explorer\\Low Rights\\ElevationPolicy\\"; |
75 | 78 |
76 // The legacy command ids for installing an application or extension. These are | 79 // The legacy command ids for installing an application or extension. These are |
77 // only here so they can be removed from the registry. | 80 // only here so they can be removed from the registry. |
78 const wchar_t kLegacyCmdInstallApp[] = L"install-application"; | 81 const wchar_t kLegacyCmdInstallApp[] = L"install-application"; |
79 const wchar_t kLegacyCmdInstallExtension[] = L"install-extension"; | 82 const wchar_t kLegacyCmdInstallExtension[] = L"install-extension"; |
80 | 83 |
84 // The prefix of the ClientState value that contains the MSI product id in the | |
85 // format "<kMSIProductIdPrefix><PRODUCTID>". | |
86 const wchar_t kMSIProductIdPrefix[] = L"EnterpriseProduct"; | |
87 | |
88 // The common path for uninstall registry entries that show up in the | |
89 // "Add/Remove Programs" dialog and its later incarnations. | |
90 const wchar_t kUninstallRegPathRoot[] = | |
91 L"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\"; | |
92 | |
93 // This is the path to the MSI user data cache, which should probably never be | |
94 // tampered with but which we'll try tweaking anyway. This is used as a printf | |
95 // format string with the token to be replaced by an MSI user data id generated | |
96 // by ConvertGUIDToMSIUserDataFormat(). Other items of note here are that this | |
97 // hard-codes the Local System SID meaning that this is strictly only usable for | |
98 // system-level installs. This would need to change for http://crbug.com/111058 | |
99 // to be fixed. | |
100 const wchar_t kMSIUserDataCacheRoot[] = | |
101 L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Installer\\UserData\\" | |
102 L"S-1-5-18\\Products\\%ls\\InstallProperties"; | |
103 | |
81 void GetOldIELowRightsElevationPolicyKeyPath(base::string16* key_path) { | 104 void GetOldIELowRightsElevationPolicyKeyPath(base::string16* key_path) { |
82 key_path->assign(kElevationPolicyKeyPath, | 105 key_path->assign(kElevationPolicyKeyPath, |
83 arraysize(kElevationPolicyKeyPath) - 1); | 106 arraysize(kElevationPolicyKeyPath) - 1); |
84 key_path->append(kIELowRightsPolicyOldGuid, | 107 key_path->append(kIELowRightsPolicyOldGuid, |
85 arraysize(kIELowRightsPolicyOldGuid)- 1); | 108 arraysize(kIELowRightsPolicyOldGuid)- 1); |
86 } | 109 } |
87 | 110 |
88 // Local helper to call AddRegisterComDllWorkItems for all DLLs in a set of | 111 // Local helper to call AddRegisterComDllWorkItems for all DLLs in a set of |
89 // products managed by a given package. | 112 // products managed by a given package. |
90 // |old_version| can be NULL to indicate no Chrome is currently installed. | 113 // |old_version| can be NULL to indicate no Chrome is currently installed. |
(...skipping 574 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
665 scoped_ptr<WorkItemList> no_rollback_list( | 688 scoped_ptr<WorkItemList> no_rollback_list( |
666 WorkItem::CreateNoRollbackWorkItemList()); | 689 WorkItem::CreateNoRollbackWorkItemList()); |
667 AddUninstallDelegateExecuteWorkItems( | 690 AddUninstallDelegateExecuteWorkItems( |
668 HKEY_CURRENT_USER, google_chrome_delegate_execute_path, | 691 HKEY_CURRENT_USER, google_chrome_delegate_execute_path, |
669 no_rollback_list.get()); | 692 no_rollback_list.get()); |
670 list->AddWorkItem(no_rollback_list.release()); | 693 list->AddWorkItem(no_rollback_list.release()); |
671 VLOG(1) << "Added deletion items for bad Canary registrations."; | 694 VLOG(1) << "Added deletion items for bad Canary registrations."; |
672 } | 695 } |
673 } | 696 } |
674 | 697 |
698 // Returns the MSI product ID from the ClientState key that is populated for MSI | |
699 // installs. This property is encoded in a value name whose format is | |
700 // "EnterpriseId<GUID>" where <GUID> is the MSI product id. <GUID> is in the | |
701 // format XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX. The id will be returned if found | |
702 // otherwise this method will return an empty string. | |
703 // | |
704 // This format is strange and its provenance is shrouded in mystery but it has | |
705 // the data we need, so use it. | |
706 base::string16 ExtractMSIProductId(const InstallerState& installer_state, | |
707 const Product& product) { | |
708 HKEY reg_root = installer_state.root_key(); | |
709 BrowserDistribution* dist = product.distribution(); | |
710 DCHECK(dist); | |
711 | |
712 base::win::RegistryValueIterator value_iter(reg_root, | |
713 dist->GetStateKey().c_str()); | |
714 for (; value_iter.Valid(); ++value_iter) { | |
715 base::string16 value_name(value_iter.Name()); | |
716 if (StartsWith(value_name, kMSIProductIdPrefix, false)) | |
grt (UTC plus 2)
2014/12/01 16:19:30
uber-nit: "false /* !case_sensitive */))"
| |
717 return value_name.substr(arraysize(kMSIProductIdPrefix) - 1); | |
718 } | |
719 return base::string16(); | |
720 } | |
721 | |
675 } // namespace | 722 } // namespace |
676 | 723 |
677 // This method adds work items to create (or update) Chrome uninstall entry in | 724 // This method adds work items to create (or update) Chrome uninstall entry in |
678 // either the Control Panel->Add/Remove Programs list or in the Omaha client | 725 // either the Control Panel->Add/Remove Programs list or in the Omaha client |
679 // state key if running under an MSI installer. | 726 // state key if running under an MSI installer. |
680 void AddUninstallShortcutWorkItems(const InstallerState& installer_state, | 727 void AddUninstallShortcutWorkItems(const InstallerState& installer_state, |
681 const base::FilePath& setup_path, | 728 const base::FilePath& setup_path, |
682 const Version& new_version, | 729 const Version& new_version, |
683 const Product& product, | 730 const Product& product, |
684 WorkItemList* install_list) { | 731 WorkItemList* install_list) { |
(...skipping 29 matching lines...) Expand all Loading... | |
714 true); | 761 true); |
715 install_list->AddSetRegValueWorkItem( | 762 install_list->AddSetRegValueWorkItem( |
716 reg_root, | 763 reg_root, |
717 update_state_key, | 764 update_state_key, |
718 KEY_WOW64_32KEY, | 765 KEY_WOW64_32KEY, |
719 installer::kUninstallArgumentsField, | 766 installer::kUninstallArgumentsField, |
720 uninstall_arguments.GetCommandLineString(), | 767 uninstall_arguments.GetCommandLineString(), |
721 true); | 768 true); |
722 | 769 |
723 // MSI installations will manage their own uninstall shortcuts. | 770 // MSI installations will manage their own uninstall shortcuts. |
724 if (!installer_state.is_msi() && product.ShouldCreateUninstallEntry()) { | 771 if (product.ShouldCreateUninstallEntry()) { |
725 // We need to quote the command line for the Add/Remove Programs dialog. | 772 if (!installer_state.is_msi()) { |
726 CommandLine quoted_uninstall_cmd(installer_path); | 773 // We need to quote the command line for the Add/Remove Programs dialog. |
727 DCHECK_EQ(quoted_uninstall_cmd.GetCommandLineString()[0], '"'); | 774 CommandLine quoted_uninstall_cmd(installer_path); |
728 quoted_uninstall_cmd.AppendArguments(uninstall_arguments, false); | 775 DCHECK_EQ(quoted_uninstall_cmd.GetCommandLineString()[0], '"'); |
776 quoted_uninstall_cmd.AppendArguments(uninstall_arguments, false); | |
729 | 777 |
730 base::string16 uninstall_reg = browser_dist->GetUninstallRegPath(); | 778 base::string16 uninstall_reg = browser_dist->GetUninstallRegPath(); |
731 install_list->AddCreateRegKeyWorkItem( | 779 install_list->AddCreateRegKeyWorkItem(reg_root, uninstall_reg, |
732 reg_root, uninstall_reg, KEY_WOW64_32KEY); | 780 KEY_WOW64_32KEY); |
733 install_list->AddSetRegValueWorkItem(reg_root, | |
734 uninstall_reg, | |
735 KEY_WOW64_32KEY, | |
736 installer::kUninstallDisplayNameField, | |
737 browser_dist->GetDisplayName(), | |
738 true); | |
739 install_list->AddSetRegValueWorkItem( | |
740 reg_root, | |
741 uninstall_reg, | |
742 KEY_WOW64_32KEY, | |
743 installer::kUninstallStringField, | |
744 quoted_uninstall_cmd.GetCommandLineString(), | |
745 true); | |
746 install_list->AddSetRegValueWorkItem(reg_root, | |
747 uninstall_reg, | |
748 KEY_WOW64_32KEY, | |
749 L"InstallLocation", | |
750 install_path.value(), | |
751 true); | |
752 | |
753 BrowserDistribution* dist = product.distribution(); | |
754 base::string16 chrome_icon = ShellUtil::FormatIconLocation( | |
755 install_path.Append(dist->GetIconFilename()).value(), | |
756 dist->GetIconIndex(BrowserDistribution::SHORTCUT_CHROME)); | |
757 install_list->AddSetRegValueWorkItem(reg_root, | |
758 uninstall_reg, | |
759 KEY_WOW64_32KEY, | |
760 L"DisplayIcon", | |
761 chrome_icon, | |
762 true); | |
763 install_list->AddSetRegValueWorkItem(reg_root, | |
764 uninstall_reg, | |
765 KEY_WOW64_32KEY, | |
766 L"NoModify", | |
767 static_cast<DWORD>(1), | |
768 true); | |
769 install_list->AddSetRegValueWorkItem(reg_root, | |
770 uninstall_reg, | |
771 KEY_WOW64_32KEY, | |
772 L"NoRepair", | |
773 static_cast<DWORD>(1), | |
774 true); | |
775 | |
776 install_list->AddSetRegValueWorkItem(reg_root, | |
777 uninstall_reg, | |
778 KEY_WOW64_32KEY, | |
779 L"Publisher", | |
780 browser_dist->GetPublisherName(), | |
781 true); | |
782 install_list->AddSetRegValueWorkItem(reg_root, | |
783 uninstall_reg, | |
784 KEY_WOW64_32KEY, | |
785 L"Version", | |
786 ASCIIToUTF16(new_version.GetString()), | |
787 true); | |
788 install_list->AddSetRegValueWorkItem(reg_root, | |
789 uninstall_reg, | |
790 KEY_WOW64_32KEY, | |
791 L"DisplayVersion", | |
792 ASCIIToUTF16(new_version.GetString()), | |
793 true); | |
794 // TODO(wfh): Ensure that this value is preserved in the 64-bit hive when | |
795 // 64-bit installs place the uninstall information into the 64-bit registry. | |
796 install_list->AddSetRegValueWorkItem(reg_root, | |
797 uninstall_reg, | |
798 KEY_WOW64_32KEY, | |
799 L"InstallDate", | |
800 InstallUtil::GetCurrentDate(), | |
801 false); | |
802 | |
803 const std::vector<uint16>& version_components = new_version.components(); | |
804 if (version_components.size() == 4) { | |
805 // Our version should be in major.minor.build.rev. | |
806 install_list->AddSetRegValueWorkItem( | 781 install_list->AddSetRegValueWorkItem( |
807 reg_root, | 782 reg_root, uninstall_reg, KEY_WOW64_32KEY, |
808 uninstall_reg, | 783 installer::kUninstallDisplayNameField, browser_dist->GetDisplayName(), |
809 KEY_WOW64_32KEY, | |
810 L"VersionMajor", | |
811 static_cast<DWORD>(version_components[2]), | |
812 true); | 784 true); |
813 install_list->AddSetRegValueWorkItem( | 785 install_list->AddSetRegValueWorkItem( |
814 reg_root, | 786 reg_root, uninstall_reg, KEY_WOW64_32KEY, |
815 uninstall_reg, | 787 installer::kUninstallStringField, |
816 KEY_WOW64_32KEY, | 788 quoted_uninstall_cmd.GetCommandLineString(), true); |
817 L"VersionMinor", | 789 install_list->AddSetRegValueWorkItem(reg_root, uninstall_reg, |
818 static_cast<DWORD>(version_components[3]), | 790 KEY_WOW64_32KEY, L"InstallLocation", |
819 true); | 791 install_path.value(), true); |
792 | |
793 BrowserDistribution* dist = product.distribution(); | |
794 base::string16 chrome_icon = ShellUtil::FormatIconLocation( | |
795 install_path.Append(dist->GetIconFilename()).value(), | |
796 dist->GetIconIndex(BrowserDistribution::SHORTCUT_CHROME)); | |
797 install_list->AddSetRegValueWorkItem(reg_root, uninstall_reg, | |
798 KEY_WOW64_32KEY, L"DisplayIcon", | |
799 chrome_icon, true); | |
800 install_list->AddSetRegValueWorkItem(reg_root, uninstall_reg, | |
801 KEY_WOW64_32KEY, L"NoModify", | |
802 static_cast<DWORD>(1), true); | |
803 install_list->AddSetRegValueWorkItem(reg_root, uninstall_reg, | |
804 KEY_WOW64_32KEY, L"NoRepair", | |
805 static_cast<DWORD>(1), true); | |
806 | |
807 install_list->AddSetRegValueWorkItem( | |
808 reg_root, uninstall_reg, KEY_WOW64_32KEY, L"Publisher", | |
809 browser_dist->GetPublisherName(), true); | |
810 install_list->AddSetRegValueWorkItem( | |
811 reg_root, uninstall_reg, KEY_WOW64_32KEY, L"Version", | |
812 ASCIIToUTF16(new_version.GetString()), true); | |
813 install_list->AddSetRegValueWorkItem( | |
814 reg_root, uninstall_reg, KEY_WOW64_32KEY, L"DisplayVersion", | |
815 ASCIIToUTF16(new_version.GetString()), true); | |
816 // TODO(wfh): Ensure that this value is preserved in the 64-bit hive when | |
817 // 64-bit installs place the uninstall information into the 64-bit | |
818 // registry. | |
819 install_list->AddSetRegValueWorkItem( | |
820 reg_root, uninstall_reg, KEY_WOW64_32KEY, L"InstallDate", | |
821 InstallUtil::GetCurrentDate(), false); | |
822 | |
823 const std::vector<uint16>& version_components = new_version.components(); | |
824 if (version_components.size() == 4) { | |
825 // Our version should be in major.minor.build.rev. | |
826 install_list->AddSetRegValueWorkItem( | |
827 reg_root, uninstall_reg, KEY_WOW64_32KEY, L"VersionMajor", | |
828 static_cast<DWORD>(version_components[2]), true); | |
829 install_list->AddSetRegValueWorkItem( | |
830 reg_root, uninstall_reg, KEY_WOW64_32KEY, L"VersionMinor", | |
831 static_cast<DWORD>(version_components[3]), true); | |
832 } | |
833 } else { | |
834 // This is an MSI install. Largely, leave all uninstall shortcuts and the | |
835 // like up to the MSI machinery EXCEPT for the DisplayVersion property. | |
836 // | |
837 // Due to reasons, the Chrome version number is wider than can fit inside | |
838 // the <8bits>.<16bits>.<8bits> allotted to MSI version numbers. To make | |
839 // things work the A.B.C.D Chrome version is lossily encoded into an X.Y.Z | |
840 // version, dropping the unneeded A and B terms. For full details, see | |
841 // https://code.google.com/p/chromium/issues/detail?id=67348#c62 | |
842 // | |
843 // The upshot of this is that Chrome MSIs have a different visible version | |
844 // than actual Chrome releases which causes trouble with some workflows. | |
845 // To help mitigate this, attempt to keep the DisplayVersion property in | |
846 // sync for MSI installs in both the Add/Remove Programs dialog and the | |
847 // corresponding MSI user data cache. | |
848 | |
849 // Figure out MSI ProductID by looking in ClientState. | |
850 // The ProductID is encoded as a key named "EnterpriseProduct<ProductID>". | |
851 base::string16 msi_product_id( | |
852 ExtractMSIProductId(installer_state, product)); | |
853 if (!msi_product_id.empty()) { | |
854 base::string16 uninstall_reg_path(kUninstallRegPathRoot); | |
855 uninstall_reg_path.append(L"{"); | |
856 uninstall_reg_path.append(msi_product_id); | |
857 uninstall_reg_path.append(L"}"); | |
858 | |
859 install_list->AddCreateRegKeyWorkItem(reg_root, uninstall_reg_path, | |
860 WorkItem::kWow64Default); | |
861 install_list->AddSetRegValueWorkItem( | |
862 reg_root, uninstall_reg_path, WorkItem::kWow64Default, | |
863 installer::kUninstallDisplayVersionField, | |
864 base::ASCIIToUTF16(new_version.GetString()), true)-> | |
865 set_ignore_failure(true); | |
866 | |
867 // Also fix up the MSI user data cache. This is a little hacky, there | |
868 // may be a better way and I am not certain this won't cause undesired | |
869 // side-effects. Note that the user data cache registry path includes | |
870 // the product id without dashes. Also note that the | |
871 // kMSIUserDataCacheRoot currently hardcodes the local system SID, which | |
872 // will need to be changed for user-level MSI installs to happen as | |
873 // tracked by http://crbug.com/111058. Leave a DCHECK here to warn those | |
874 // who next venture here to use a correct SID in kMSIUserDataCacheRoot. | |
875 DCHECK(installer_state.system_install()); | |
876 | |
877 base::string16 msi_user_data_product_id( | |
878 ConvertGUIDToMSIUserDataFormat(msi_product_id)); | |
879 if (!msi_user_data_product_id.empty()) { | |
880 base::string16 msi_cache_reg_path(base::StringPrintf( | |
881 kMSIUserDataCacheRoot, msi_user_data_product_id.c_str())); | |
882 | |
883 install_list->AddSetRegValueWorkItem( | |
884 reg_root, msi_cache_reg_path, KEY_WOW64_64KEY, | |
885 installer::kUninstallDisplayVersionField, | |
886 base::ASCIIToUTF16(new_version.GetString()), true)-> | |
887 set_ignore_failure(true); | |
888 } else { | |
889 VLOG(1) << "Failed to convert MSI user data id from product id: " | |
890 << msi_product_id; | |
891 } | |
892 } else { | |
893 VLOG(1) << "Failed to extract MSI product id."; | |
894 } | |
820 } | 895 } |
821 } | 896 } |
822 } | 897 } |
823 | 898 |
824 // Create Version key for a product (if not already present) and sets the new | 899 // Create Version key for a product (if not already present) and sets the new |
825 // product version as the last step. | 900 // product version as the last step. |
826 void AddVersionKeyWorkItems(HKEY root, | 901 void AddVersionKeyWorkItems(HKEY root, |
827 const base::string16& version_key, | 902 const base::string16& version_key, |
828 const base::string16& product_name, | 903 const base::string16& product_name, |
829 const Version& new_version, | 904 const Version& new_version, |
(...skipping 833 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1663 | 1738 |
1664 // Unconditionally remove the legacy Quick Enable command from the binaries. | 1739 // Unconditionally remove the legacy Quick Enable command from the binaries. |
1665 // Do this even if multi-install Chrome isn't installed to ensure that it is | 1740 // Do this even if multi-install Chrome isn't installed to ensure that it is |
1666 // not left behind in any case. | 1741 // not left behind in any case. |
1667 work_item_list->AddDeleteRegKeyWorkItem( | 1742 work_item_list->AddDeleteRegKeyWorkItem( |
1668 installer_state.root_key(), cmd_key, KEY_WOW64_32KEY) | 1743 installer_state.root_key(), cmd_key, KEY_WOW64_32KEY) |
1669 ->set_log_message("removing " + base::UTF16ToASCII(kCmdQuickEnableCf) + | 1744 ->set_log_message("removing " + base::UTF16ToASCII(kCmdQuickEnableCf) + |
1670 " command"); | 1745 " command"); |
1671 } | 1746 } |
1672 | 1747 |
1748 // Converts a correctly formatted guid thusly: | |
1749 // 12345678-90ab-cdef-ghij-klmnopqrstuv -> 87654321ba09fedchgjilknmporqtsvu | |
1750 // This reverses the string of the first three terms and inverts the bytes of | |
1751 // the last two. It also removes the dashes. It expects the input to NOT be | |
1752 // wrapped in braces. | |
1753 // Returns an empty string on failure. | |
1754 base::string16 ConvertGUIDToMSIUserDataFormat(const base::string16& guid) { | |
1755 // Perform some very mild validation of the input. | |
1756 if (guid.size() != 36) | |
1757 return base::string16(); | |
1758 | |
1759 base::string16 msi_formatted_guid; | |
1760 int token_count = 0; | |
1761 base::WStringTokenizer tokenizer(guid, L"-"); | |
1762 while (tokenizer.GetNext()) { | |
1763 // There should be exactly five tokens, bail if not. | |
1764 if (token_count >= 5) | |
1765 return base::string16(); | |
1766 | |
1767 base::string16 token(tokenizer.token()); | |
1768 if (token_count < 3) { | |
1769 // For the first three tokens, just reverse the characters. | |
1770 std::reverse(token.begin(), token.end()); | |
1771 msi_formatted_guid += token; | |
1772 } else { | |
1773 // The last two tokens need to be of even length. | |
1774 if (token.size() % 2) | |
1775 return base::string16(); | |
1776 // Swap the halves of each byte (i.e. pair of chars). I don't even. | |
1777 for (size_t i = 0; i < token.size(); i += 2) { | |
1778 msi_formatted_guid += token[i+1]; | |
1779 msi_formatted_guid += token[i]; | |
1780 } | |
1781 } | |
1782 token_count++; | |
1783 } | |
1784 | |
1785 return (token_count == 5) ? msi_formatted_guid : base::string16(); | |
1786 } | |
1787 | |
1673 } // namespace installer | 1788 } // namespace installer |
OLD | NEW |