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 561 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
652 scoped_ptr<WorkItemList> no_rollback_list( | 675 scoped_ptr<WorkItemList> no_rollback_list( |
653 WorkItem::CreateNoRollbackWorkItemList()); | 676 WorkItem::CreateNoRollbackWorkItemList()); |
654 AddUninstallDelegateExecuteWorkItems( | 677 AddUninstallDelegateExecuteWorkItems( |
655 HKEY_CURRENT_USER, google_chrome_delegate_execute_path, | 678 HKEY_CURRENT_USER, google_chrome_delegate_execute_path, |
656 no_rollback_list.get()); | 679 no_rollback_list.get()); |
657 list->AddWorkItem(no_rollback_list.release()); | 680 list->AddWorkItem(no_rollback_list.release()); |
658 VLOG(1) << "Added deletion items for bad Canary registrations."; | 681 VLOG(1) << "Added deletion items for bad Canary registrations."; |
659 } | 682 } |
660 } | 683 } |
661 | 684 |
| 685 // Returns the MSI product ID from the ClientState key that is populated for MSI |
| 686 // installs. This property is encoded in a value name whose format is |
| 687 // "EnterpriseId<GUID>" where <GUID> is the MSI product id. <GUID> is in the |
| 688 // format XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX. The id will be returned if found |
| 689 // otherwise this method will return an empty string. |
| 690 // |
| 691 // This format is strange and its provenance is shrouded in mystery but it has |
| 692 // the data we need, so use it. |
| 693 base::string16 ExtractMSIProductId(const InstallerState& installer_state, |
| 694 const Product& product) { |
| 695 HKEY reg_root = installer_state.root_key(); |
| 696 BrowserDistribution* dist = product.distribution(); |
| 697 DCHECK(dist); |
| 698 |
| 699 base::win::RegistryValueIterator value_iter(reg_root, |
| 700 dist->GetStateKey().c_str()); |
| 701 for (; value_iter.Valid(); ++value_iter) { |
| 702 base::string16 value_name(value_iter.Name()); |
| 703 if (StartsWith(value_name, kMSIProductIdPrefix, false)) |
| 704 return value_name.substr(arraysize(kMSIProductIdPrefix) - 1); |
| 705 } |
| 706 return base::string16(); |
| 707 } |
| 708 |
662 } // namespace | 709 } // namespace |
663 | 710 |
664 // This method adds work items to create (or update) Chrome uninstall entry in | 711 // This method adds work items to create (or update) Chrome uninstall entry in |
665 // either the Control Panel->Add/Remove Programs list or in the Omaha client | 712 // either the Control Panel->Add/Remove Programs list or in the Omaha client |
666 // state key if running under an MSI installer. | 713 // state key if running under an MSI installer. |
667 void AddUninstallShortcutWorkItems(const InstallerState& installer_state, | 714 void AddUninstallShortcutWorkItems(const InstallerState& installer_state, |
668 const base::FilePath& setup_path, | 715 const base::FilePath& setup_path, |
669 const Version& new_version, | 716 const Version& new_version, |
670 const Product& product, | 717 const Product& product, |
671 WorkItemList* install_list) { | 718 WorkItemList* install_list) { |
(...skipping 29 matching lines...) Expand all Loading... |
701 true); | 748 true); |
702 install_list->AddSetRegValueWorkItem( | 749 install_list->AddSetRegValueWorkItem( |
703 reg_root, | 750 reg_root, |
704 update_state_key, | 751 update_state_key, |
705 KEY_WOW64_32KEY, | 752 KEY_WOW64_32KEY, |
706 installer::kUninstallArgumentsField, | 753 installer::kUninstallArgumentsField, |
707 uninstall_arguments.GetCommandLineString(), | 754 uninstall_arguments.GetCommandLineString(), |
708 true); | 755 true); |
709 | 756 |
710 // MSI installations will manage their own uninstall shortcuts. | 757 // MSI installations will manage their own uninstall shortcuts. |
711 if (!installer_state.is_msi() && product.ShouldCreateUninstallEntry()) { | 758 if (product.ShouldCreateUninstallEntry()) { |
712 // We need to quote the command line for the Add/Remove Programs dialog. | 759 if (!installer_state.is_msi()) { |
713 base::CommandLine quoted_uninstall_cmd(installer_path); | 760 // We need to quote the command line for the Add/Remove Programs dialog. |
714 DCHECK_EQ(quoted_uninstall_cmd.GetCommandLineString()[0], '"'); | 761 base::CommandLine quoted_uninstall_cmd(installer_path); |
715 quoted_uninstall_cmd.AppendArguments(uninstall_arguments, false); | 762 DCHECK_EQ(quoted_uninstall_cmd.GetCommandLineString()[0], '"'); |
| 763 quoted_uninstall_cmd.AppendArguments(uninstall_arguments, false); |
716 | 764 |
717 base::string16 uninstall_reg = browser_dist->GetUninstallRegPath(); | 765 base::string16 uninstall_reg = browser_dist->GetUninstallRegPath(); |
718 install_list->AddCreateRegKeyWorkItem( | 766 install_list->AddCreateRegKeyWorkItem(reg_root, uninstall_reg, |
719 reg_root, uninstall_reg, KEY_WOW64_32KEY); | 767 KEY_WOW64_32KEY); |
720 install_list->AddSetRegValueWorkItem(reg_root, | |
721 uninstall_reg, | |
722 KEY_WOW64_32KEY, | |
723 installer::kUninstallDisplayNameField, | |
724 browser_dist->GetDisplayName(), | |
725 true); | |
726 install_list->AddSetRegValueWorkItem( | |
727 reg_root, | |
728 uninstall_reg, | |
729 KEY_WOW64_32KEY, | |
730 installer::kUninstallStringField, | |
731 quoted_uninstall_cmd.GetCommandLineString(), | |
732 true); | |
733 install_list->AddSetRegValueWorkItem(reg_root, | |
734 uninstall_reg, | |
735 KEY_WOW64_32KEY, | |
736 L"InstallLocation", | |
737 install_path.value(), | |
738 true); | |
739 | |
740 BrowserDistribution* dist = product.distribution(); | |
741 base::string16 chrome_icon = ShellUtil::FormatIconLocation( | |
742 install_path.Append(dist->GetIconFilename()), | |
743 dist->GetIconIndex(BrowserDistribution::SHORTCUT_CHROME)); | |
744 install_list->AddSetRegValueWorkItem(reg_root, | |
745 uninstall_reg, | |
746 KEY_WOW64_32KEY, | |
747 L"DisplayIcon", | |
748 chrome_icon, | |
749 true); | |
750 install_list->AddSetRegValueWorkItem(reg_root, | |
751 uninstall_reg, | |
752 KEY_WOW64_32KEY, | |
753 L"NoModify", | |
754 static_cast<DWORD>(1), | |
755 true); | |
756 install_list->AddSetRegValueWorkItem(reg_root, | |
757 uninstall_reg, | |
758 KEY_WOW64_32KEY, | |
759 L"NoRepair", | |
760 static_cast<DWORD>(1), | |
761 true); | |
762 | |
763 install_list->AddSetRegValueWorkItem(reg_root, | |
764 uninstall_reg, | |
765 KEY_WOW64_32KEY, | |
766 L"Publisher", | |
767 browser_dist->GetPublisherName(), | |
768 true); | |
769 install_list->AddSetRegValueWorkItem(reg_root, | |
770 uninstall_reg, | |
771 KEY_WOW64_32KEY, | |
772 L"Version", | |
773 ASCIIToUTF16(new_version.GetString()), | |
774 true); | |
775 install_list->AddSetRegValueWorkItem(reg_root, | |
776 uninstall_reg, | |
777 KEY_WOW64_32KEY, | |
778 L"DisplayVersion", | |
779 ASCIIToUTF16(new_version.GetString()), | |
780 true); | |
781 // TODO(wfh): Ensure that this value is preserved in the 64-bit hive when | |
782 // 64-bit installs place the uninstall information into the 64-bit registry. | |
783 install_list->AddSetRegValueWorkItem(reg_root, | |
784 uninstall_reg, | |
785 KEY_WOW64_32KEY, | |
786 L"InstallDate", | |
787 InstallUtil::GetCurrentDate(), | |
788 false); | |
789 | |
790 const std::vector<uint16>& version_components = new_version.components(); | |
791 if (version_components.size() == 4) { | |
792 // Our version should be in major.minor.build.rev. | |
793 install_list->AddSetRegValueWorkItem( | 768 install_list->AddSetRegValueWorkItem( |
794 reg_root, | 769 reg_root, uninstall_reg, KEY_WOW64_32KEY, |
795 uninstall_reg, | 770 installer::kUninstallDisplayNameField, browser_dist->GetDisplayName(), |
796 KEY_WOW64_32KEY, | |
797 L"VersionMajor", | |
798 static_cast<DWORD>(version_components[2]), | |
799 true); | 771 true); |
800 install_list->AddSetRegValueWorkItem( | 772 install_list->AddSetRegValueWorkItem( |
801 reg_root, | 773 reg_root, uninstall_reg, KEY_WOW64_32KEY, |
802 uninstall_reg, | 774 installer::kUninstallStringField, |
803 KEY_WOW64_32KEY, | 775 quoted_uninstall_cmd.GetCommandLineString(), true); |
804 L"VersionMinor", | 776 install_list->AddSetRegValueWorkItem(reg_root, uninstall_reg, |
805 static_cast<DWORD>(version_components[3]), | 777 KEY_WOW64_32KEY, L"InstallLocation", |
806 true); | 778 install_path.value(), true); |
| 779 |
| 780 BrowserDistribution* dist = product.distribution(); |
| 781 base::string16 chrome_icon = ShellUtil::FormatIconLocation( |
| 782 install_path.Append(dist->GetIconFilename()).value(), |
| 783 dist->GetIconIndex(BrowserDistribution::SHORTCUT_CHROME)); |
| 784 install_list->AddSetRegValueWorkItem(reg_root, uninstall_reg, |
| 785 KEY_WOW64_32KEY, L"DisplayIcon", |
| 786 chrome_icon, true); |
| 787 install_list->AddSetRegValueWorkItem(reg_root, uninstall_reg, |
| 788 KEY_WOW64_32KEY, L"NoModify", |
| 789 static_cast<DWORD>(1), true); |
| 790 install_list->AddSetRegValueWorkItem(reg_root, uninstall_reg, |
| 791 KEY_WOW64_32KEY, L"NoRepair", |
| 792 static_cast<DWORD>(1), true); |
| 793 |
| 794 install_list->AddSetRegValueWorkItem( |
| 795 reg_root, uninstall_reg, KEY_WOW64_32KEY, L"Publisher", |
| 796 browser_dist->GetPublisherName(), true); |
| 797 install_list->AddSetRegValueWorkItem( |
| 798 reg_root, uninstall_reg, KEY_WOW64_32KEY, L"Version", |
| 799 ASCIIToUTF16(new_version.GetString()), true); |
| 800 install_list->AddSetRegValueWorkItem( |
| 801 reg_root, uninstall_reg, KEY_WOW64_32KEY, L"DisplayVersion", |
| 802 ASCIIToUTF16(new_version.GetString()), true); |
| 803 // TODO(wfh): Ensure that this value is preserved in the 64-bit hive when |
| 804 // 64-bit installs place the uninstall information into the 64-bit |
| 805 // registry. |
| 806 install_list->AddSetRegValueWorkItem( |
| 807 reg_root, uninstall_reg, KEY_WOW64_32KEY, L"InstallDate", |
| 808 InstallUtil::GetCurrentDate(), false); |
| 809 |
| 810 const std::vector<uint16>& version_components = new_version.components(); |
| 811 if (version_components.size() == 4) { |
| 812 // Our version should be in major.minor.build.rev. |
| 813 install_list->AddSetRegValueWorkItem( |
| 814 reg_root, uninstall_reg, KEY_WOW64_32KEY, L"VersionMajor", |
| 815 static_cast<DWORD>(version_components[2]), true); |
| 816 install_list->AddSetRegValueWorkItem( |
| 817 reg_root, uninstall_reg, KEY_WOW64_32KEY, L"VersionMinor", |
| 818 static_cast<DWORD>(version_components[3]), true); |
| 819 } |
| 820 } else { |
| 821 // This is an MSI install. Largely, leave all uninstall shortcuts and the |
| 822 // like up to the MSI machinery EXCEPT for the DisplayVersion property. |
| 823 // |
| 824 // Due to reasons, the Chrome version number is wider than can fit inside |
| 825 // the <8bits>.<16bits>.<8bits> allotted to MSI version numbers. To make |
| 826 // things work the A.B.C.D Chrome version is lossily encoded into an X.Y.Z |
| 827 // version, dropping the unneeded A and B terms. For full details, see |
| 828 // https://code.google.com/p/chromium/issues/detail?id=67348#c62 |
| 829 // |
| 830 // The upshot of this is that Chrome MSIs have a different visible version |
| 831 // than actual Chrome releases which causes trouble with some workflows. |
| 832 // To help mitigate this, attempt to keep the DisplayVersion property in |
| 833 // sync for MSI installs in both the Add/Remove Programs dialog and the |
| 834 // corresponding MSI user data cache. |
| 835 |
| 836 // Figure out MSI ProductID by looking in ClientState. |
| 837 // The ProductID is encoded as a key named "EnterpriseProduct<ProductID>". |
| 838 base::string16 msi_product_id( |
| 839 ExtractMSIProductId(installer_state, product)); |
| 840 if (!msi_product_id.empty()) { |
| 841 base::string16 uninstall_reg_path(kUninstallRegPathRoot); |
| 842 uninstall_reg_path.append(L"{"); |
| 843 uninstall_reg_path.append(msi_product_id); |
| 844 uninstall_reg_path.append(L"}"); |
| 845 |
| 846 install_list->AddCreateRegKeyWorkItem(reg_root, uninstall_reg_path, |
| 847 WorkItem::kWow64Default); |
| 848 install_list->AddSetRegValueWorkItem( |
| 849 reg_root, uninstall_reg_path, WorkItem::kWow64Default, |
| 850 installer::kUninstallDisplayVersionField, |
| 851 base::ASCIIToUTF16(new_version.GetString()), true)-> |
| 852 set_ignore_failure(true); |
| 853 |
| 854 // Also fix up the MSI user data cache. This is a little hacky, there |
| 855 // may be a better way and I am not certain this won't cause undesired |
| 856 // side-effects. Note that the user data cache registry path includes |
| 857 // the product id without dashes. Also note that the |
| 858 // kMSIUserDataCacheRoot currently hardcodes the local system SID, which |
| 859 // will need to be changed for user-level MSI installs to happen as |
| 860 // tracked by http://crbug.com/111058. Leave a DCHECK here to warn those |
| 861 // who next venture here to use a correct SID in kMSIUserDataCacheRoot. |
| 862 DCHECK(installer_state.system_install()); |
| 863 |
| 864 base::string16 msi_user_data_product_id( |
| 865 ConvertGUIDToMSIUserDataFormat(msi_product_id)); |
| 866 if (!msi_user_data_product_id.empty()) { |
| 867 base::string16 msi_cache_reg_path(base::StringPrintf( |
| 868 kMSIUserDataCacheRoot, msi_user_data_product_id.c_str())); |
| 869 |
| 870 install_list->AddSetRegValueWorkItem( |
| 871 reg_root, msi_cache_reg_path, KEY_WOW64_64KEY, |
| 872 installer::kUninstallDisplayVersionField, |
| 873 base::ASCIIToUTF16(new_version.GetString()), true)-> |
| 874 set_ignore_failure(true); |
| 875 } else { |
| 876 LOG(DFATAL) << "Failed to convert MSI user data id from product id: " |
| 877 << msi_product_id; |
| 878 } |
| 879 } else { |
| 880 LOG(ERROR) << "Failed to extract MSI product id."; |
| 881 } |
807 } | 882 } |
808 } | 883 } |
809 } | 884 } |
810 | 885 |
811 // Create Version key for a product (if not already present) and sets the new | 886 // Create Version key for a product (if not already present) and sets the new |
812 // product version as the last step. | 887 // product version as the last step. |
813 void AddVersionKeyWorkItems(HKEY root, | 888 void AddVersionKeyWorkItems(HKEY root, |
814 const base::string16& version_key, | 889 const base::string16& version_key, |
815 const base::string16& product_name, | 890 const base::string16& product_name, |
816 const Version& new_version, | 891 const Version& new_version, |
(...skipping 833 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1650 | 1725 |
1651 // Unconditionally remove the legacy Quick Enable command from the binaries. | 1726 // Unconditionally remove the legacy Quick Enable command from the binaries. |
1652 // Do this even if multi-install Chrome isn't installed to ensure that it is | 1727 // Do this even if multi-install Chrome isn't installed to ensure that it is |
1653 // not left behind in any case. | 1728 // not left behind in any case. |
1654 work_item_list->AddDeleteRegKeyWorkItem( | 1729 work_item_list->AddDeleteRegKeyWorkItem( |
1655 installer_state.root_key(), cmd_key, KEY_WOW64_32KEY) | 1730 installer_state.root_key(), cmd_key, KEY_WOW64_32KEY) |
1656 ->set_log_message("removing " + base::UTF16ToASCII(kCmdQuickEnableCf) + | 1731 ->set_log_message("removing " + base::UTF16ToASCII(kCmdQuickEnableCf) + |
1657 " command"); | 1732 " command"); |
1658 } | 1733 } |
1659 | 1734 |
| 1735 // Converts a correctly formatted guid thusly: |
| 1736 // 12345678-90ab-cdef-ghij-klmnopqrstuv -> 87654321ba09fedchgjilknmporqtsvu |
| 1737 // This reverses the string of the first three terms and inverts the bytes of |
| 1738 // the last two. It also removes the dashes. It expects the input to NOT be |
| 1739 // wrapped in braces. |
| 1740 // Returns an empty string on failure. |
| 1741 base::string16 ConvertGUIDToMSIUserDataFormat(const base::string16& guid) { |
| 1742 // Perform some very mild validation of the input. |
| 1743 if (guid.size() != 36) |
| 1744 return base::string16(); |
| 1745 |
| 1746 base::string16 msi_formatted_guid; |
| 1747 int token_count = 0; |
| 1748 base::WStringTokenizer tokenizer(guid, L"-"); |
| 1749 while (tokenizer.GetNext()) { |
| 1750 // There should be exactly five tokens, bail if not. |
| 1751 if (token_count >= 5) |
| 1752 return base::string16(); |
| 1753 |
| 1754 base::string16 token(tokenizer.token()); |
| 1755 if (token_count < 3) { |
| 1756 // For the first three tokens, just reverse the characters. |
| 1757 std::reverse(token.begin(), token.end()); |
| 1758 msi_formatted_guid += token; |
| 1759 } else { |
| 1760 // The last two tokens need to be of even length. |
| 1761 if (token.size() % 2) |
| 1762 return base::string16(); |
| 1763 // Swap the halves of each byte (i.e. pair of chars). I don't even. |
| 1764 for (size_t i = 0; i < token.size(); i += 2) { |
| 1765 msi_formatted_guid += token[i+1]; |
| 1766 msi_formatted_guid += token[i]; |
| 1767 } |
| 1768 } |
| 1769 token_count++; |
| 1770 } |
| 1771 |
| 1772 return (token_count == 5) ? msi_formatted_guid : base::string16(); |
| 1773 } |
| 1774 |
1660 } // namespace installer | 1775 } // namespace installer |
OLD | NEW |