Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(871)

Side by Side Diff: chrome/install_static/install_util.cc

Issue 2017853002: Add functionality to the install_static library to tokenize strings and compare versions. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Add install_static_unittests to other windows bots Created 4 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 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 #include "chrome/install_static/install_util.h" 5 #include "chrome/install_static/install_util.h"
6 6
7 #include <windows.h> 7 #include <windows.h>
8 #include <assert.h> 8 #include <assert.h>
9 #include <algorithm> 9 #include <algorithm>
10 #include <iostream>
11 #include <iterator>
10 #include <memory> 12 #include <memory>
13 #include <sstream>
11 14
12 #include "base/macros.h" 15 #include "base/macros.h"
13 #include "build/build_config.h" 16 #include "build/build_config.h"
14 17
15 namespace install_static { 18 namespace install_static {
16 19
17 ProcessType g_process_type = ProcessType::UNINITIALIZED; 20 ProcessType g_process_type = ProcessType::UNINITIALIZED;
18 21
19 // TODO(ananta) 22 // TODO(ananta)
20 // http://crbug.com/604923 23 // http://crbug.com/604923
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
86 va_end(args); 89 va_end(args);
87 } 90 }
88 91
89 // Reads a string value identified by |value_to_read| from the registry path 92 // Reads a string value identified by |value_to_read| from the registry path
90 // under |key_path|. We look in HKLM or HKCU depending on whether the 93 // under |key_path|. We look in HKLM or HKCU depending on whether the
91 // |system_install| parameter is true. 94 // |system_install| parameter is true.
92 // Please note that this function only looks in the 32bit view of the registry. 95 // Please note that this function only looks in the 32bit view of the registry.
93 bool ReadKeyValueString(bool system_install, const wchar_t* key_path, 96 bool ReadKeyValueString(bool system_install, const wchar_t* key_path,
94 const wchar_t* guid, const wchar_t* value_to_read, 97 const wchar_t* guid, const wchar_t* value_to_read,
95 base::string16* value_out) { 98 base::string16* value_out) {
96 HKEY key = NULL; 99 HKEY key = nullptr;
97 value_out->clear(); 100 value_out->clear();
98 101
99 base::string16 full_key_path(key_path); 102 base::string16 full_key_path(key_path);
100 if (guid && *guid) { 103 if (guid && *guid) {
101 full_key_path.append(1, L'\\'); 104 full_key_path.append(1, L'\\');
102 full_key_path.append(guid); 105 full_key_path.append(guid);
103 } 106 }
104 107
105 if (::RegOpenKeyEx(system_install ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER, 108 if (::RegOpenKeyEx(system_install ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER,
106 full_key_path.c_str(), 0, 109 full_key_path.c_str(), 0,
(...skipping 30 matching lines...) Expand all
137 return result == ERROR_SUCCESS; 140 return result == ERROR_SUCCESS;
138 } 141 }
139 142
140 // Reads a DWORD value identified by |value_to_read| from the registry path 143 // Reads a DWORD value identified by |value_to_read| from the registry path
141 // under |key_path|. We look in HKLM or HKCU depending on whether the 144 // under |key_path|. We look in HKLM or HKCU depending on whether the
142 // |system_install| parameter is true. 145 // |system_install| parameter is true.
143 // Please note that this function only looks in the 32bit view of the registry. 146 // Please note that this function only looks in the 32bit view of the registry.
144 bool ReadKeyValueDW(bool system_install, const wchar_t* key_path, 147 bool ReadKeyValueDW(bool system_install, const wchar_t* key_path,
145 base::string16 guid, const wchar_t* value_to_read, 148 base::string16 guid, const wchar_t* value_to_read,
146 DWORD* value_out) { 149 DWORD* value_out) {
147 HKEY key = NULL; 150 HKEY key = nullptr;
148 *value_out = 0; 151 *value_out = 0;
149 152
150 base::string16 full_key_path(key_path); 153 base::string16 full_key_path(key_path);
151 full_key_path.append(1, L'\\'); 154 full_key_path.append(1, L'\\');
152 full_key_path.append(guid); 155 full_key_path.append(guid);
153 156
154 if (::RegOpenKeyEx(system_install ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER, 157 if (::RegOpenKeyEx(system_install ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER,
155 full_key_path.c_str(), 0, 158 full_key_path.c_str(), 0,
156 KEY_QUERY_VALUE | KEY_WOW64_32KEY, &key) != 159 KEY_QUERY_VALUE | KEY_WOW64_32KEY, &key) !=
157 ERROR_SUCCESS) { 160 ERROR_SUCCESS) {
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after
248 } 251 }
249 252
250 // Returns the executable path for the current process. 253 // Returns the executable path for the current process.
251 base::string16 GetCurrentProcessExePath() { 254 base::string16 GetCurrentProcessExePath() {
252 wchar_t exe_path[MAX_PATH]; 255 wchar_t exe_path[MAX_PATH];
253 if (GetModuleFileName(nullptr, exe_path, arraysize(exe_path)) == 0) 256 if (GetModuleFileName(nullptr, exe_path, arraysize(exe_path)) == 0)
254 return base::string16(); 257 return base::string16();
255 return exe_path; 258 return exe_path;
256 } 259 }
257 260
258 // UTF8 to UTF16 and vice versa conversion helpers. We cannot use the base
259 // string conversion utilities here as they bring about a dependency on
260 // user32.dll which is not allowed in this file.
261
262 // Convert a UTF16 string to an UTF8 string.
263 std::string utf16_to_utf8(const base::string16 &source) {
264 if (source.empty())
265 return std::string();
266 int size = ::WideCharToMultiByte(CP_UTF8, 0, &source[0],
267 static_cast<int>(source.size()), nullptr, 0, nullptr, nullptr);
268 std::string result(size, '\0');
269 if (::WideCharToMultiByte(CP_UTF8, 0, &source[0],
270 static_cast<int>(source.size()), &result[0], size, nullptr,
271 nullptr) != size) {
272 assert(false);
273 return std::string();
274 }
275 return result;
276 }
277
278 // Convert a UTF8 string to a UTF16 string.
279 base::string16 utf8_to_string16(const std::string &source) {
280 if (source.empty())
281 return base::string16();
282 int size = ::MultiByteToWideChar(CP_UTF8, 0, &source[0],
283 static_cast<int>(source.size()), nullptr, 0);
284 base::string16 result(size, L'\0');
285 if (::MultiByteToWideChar(CP_UTF8, 0, &source[0],
286 static_cast<int>(source.size()), &result[0], size) != size) {
287 assert(false);
288 return base::string16();
289 }
290 return result;
291 }
292
293 bool RecursiveDirectoryCreate(const base::string16& full_path) { 261 bool RecursiveDirectoryCreate(const base::string16& full_path) {
294 // If the path exists, we've succeeded if it's a directory, failed otherwise. 262 // If the path exists, we've succeeded if it's a directory, failed otherwise.
295 const wchar_t* full_path_str = full_path.c_str(); 263 const wchar_t* full_path_str = full_path.c_str();
296 DWORD file_attributes = ::GetFileAttributes(full_path_str); 264 DWORD file_attributes = ::GetFileAttributes(full_path_str);
297 if (file_attributes != INVALID_FILE_ATTRIBUTES) { 265 if (file_attributes != INVALID_FILE_ATTRIBUTES) {
298 if ((file_attributes & FILE_ATTRIBUTE_DIRECTORY) != 0) { 266 if ((file_attributes & FILE_ATTRIBUTE_DIRECTORY) != 0) {
299 Trace(L"%hs( %ls directory exists )\n", __FUNCTION__, full_path_str); 267 Trace(L"%hs( %ls directory exists )\n", __FUNCTION__, full_path_str);
300 return true; 268 return true;
301 } 269 }
302 Trace(L"%hs( %ls directory conflicts with an existing file. )\n", 270 Trace(L"%hs( %ls directory conflicts with an existing file. )\n",
303 __FUNCTION__, full_path_str); 271 __FUNCTION__, full_path_str);
304 return false; 272 return false;
305 } 273 }
306 274
307 // Invariant: Path does not exist as file or directory. 275 // Invariant: Path does not exist as file or directory.
308 276
309 // Attempt to create the parent recursively. This will immediately return 277 // Attempt to create the parent recursively. This will immediately return
310 // true if it already exists, otherwise will create all required parent 278 // true if it already exists, otherwise will create all required parent
311 // directories starting with the highest-level missing parent. 279 // directories starting with the highest-level missing parent.
312 base::string16 parent_path; 280 base::string16 parent_path;
313 std::size_t pos = full_path.find_last_of(L"/\\"); 281 std::size_t pos = full_path.find_last_of(L"/\\");
314 if (pos != base::string16::npos) { 282 if (pos != base::string16::npos) {
315 parent_path = full_path.substr(0, pos); 283 parent_path = full_path.substr(0, pos);
316 if (!RecursiveDirectoryCreate(parent_path)) { 284 if (!RecursiveDirectoryCreate(parent_path)) {
317 Trace(L"Failed to create one of the parent directories"); 285 Trace(L"Failed to create one of the parent directories");
318 return false; 286 return false;
319 } 287 }
320 } 288 }
321 if (!::CreateDirectory(full_path_str, NULL)) { 289 if (!::CreateDirectory(full_path_str, nullptr)) {
322 DWORD error_code = ::GetLastError(); 290 DWORD error_code = ::GetLastError();
323 if (error_code == ERROR_ALREADY_EXISTS) { 291 if (error_code == ERROR_ALREADY_EXISTS) {
324 DWORD file_attributes = ::GetFileAttributes(full_path_str); 292 DWORD file_attributes = ::GetFileAttributes(full_path_str);
325 if ((file_attributes != INVALID_FILE_ATTRIBUTES) && 293 if ((file_attributes != INVALID_FILE_ATTRIBUTES) &&
326 ((file_attributes & FILE_ATTRIBUTE_DIRECTORY) != 0)) { 294 ((file_attributes & FILE_ATTRIBUTE_DIRECTORY) != 0)) {
327 // This error code ERROR_ALREADY_EXISTS doesn't indicate whether we 295 // This error code ERROR_ALREADY_EXISTS doesn't indicate whether we
328 // were racing with someone creating the same directory, or a file 296 // were racing with someone creating the same directory, or a file
329 // with the same path. If the directory exists, we lost the 297 // with the same path. If the directory exists, we lost the
330 // race to create the same directory. 298 // race to create the same directory.
331 return true; 299 return true;
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after
412 // 1. We consider current character of source. 380 // 1. We consider current character of source.
413 // 2. We ignore current character of source. 381 // 2. We ignore current character of source.
414 if (pattern[pattern_index] == L'*') { 382 if (pattern[pattern_index] == L'*') {
415 return MatchPatternImpl(source, pattern, source_index + 1, 383 return MatchPatternImpl(source, pattern, source_index + 1,
416 pattern_index) || 384 pattern_index) ||
417 MatchPatternImpl(source, pattern, source_index, pattern_index + 1); 385 MatchPatternImpl(source, pattern, source_index, pattern_index + 1);
418 } 386 }
419 return false; 387 return false;
420 } 388 }
421 389
390 // Defines the type of whitespace characters typically found in strings.
391 constexpr char kWhiteSpaces[] = " \t\n\r\f\v";
392
393 // Trim whitespaces from left & right
394 void Trim(std::string* str) {
395 str->erase(str->find_last_not_of(kWhiteSpaces) + 1);
396 str->erase(0, str->find_first_not_of(kWhiteSpaces));
397 }
398
399 bool IsValidNumber(const std::string& str) {
400 if (str.empty())
401 return false;
402 return std::all_of(str.begin(), str.end(), ::isdigit);
403 }
404
422 } // namespace 405 } // namespace
423 406
424 bool IsSxSChrome(const wchar_t* exe_path) { 407 bool IsSxSChrome(const wchar_t* exe_path) {
425 return wcsstr(exe_path, L"Chrome SxS\\Application") != NULL; 408 return wcsstr(exe_path, L"Chrome SxS\\Application") != nullptr;
426 } 409 }
427 410
428 bool IsSystemInstall(const wchar_t* exe_path) { 411 bool IsSystemInstall(const wchar_t* exe_path) {
429 wchar_t program_dir[MAX_PATH] = {}; 412 wchar_t program_dir[MAX_PATH] = {};
430 DWORD ret = ::GetEnvironmentVariable(L"PROGRAMFILES", program_dir, 413 DWORD ret = ::GetEnvironmentVariable(L"PROGRAMFILES", program_dir,
431 arraysize(program_dir)); 414 arraysize(program_dir));
432 if (ret && ret < arraysize(program_dir) && 415 if (ret && ret < arraysize(program_dir) &&
433 !wcsnicmp(exe_path, program_dir, ret)) { 416 !wcsnicmp(exe_path, program_dir, ret)) {
434 return true; 417 return true;
435 } 418 }
(...skipping 20 matching lines...) Expand all
456 439
457 bool GetCollectStatsConsent() { 440 bool GetCollectStatsConsent() {
458 return GetCollectStatsConsentImpl(GetCurrentProcessExePath()); 441 return GetCollectStatsConsentImpl(GetCurrentProcessExePath());
459 } 442 }
460 443
461 bool GetCollectStatsConsentForTesting(const base::string16& exe_path) { 444 bool GetCollectStatsConsentForTesting(const base::string16& exe_path) {
462 return GetCollectStatsConsentImpl(exe_path); 445 return GetCollectStatsConsentImpl(exe_path);
463 } 446 }
464 447
465 bool ReportingIsEnforcedByPolicy(bool* metrics_is_enforced_by_policy) { 448 bool ReportingIsEnforcedByPolicy(bool* metrics_is_enforced_by_policy) {
466 HKEY key = NULL; 449 HKEY key = nullptr;
467 DWORD value = 0; 450 DWORD value = 0;
468 BYTE* value_bytes = reinterpret_cast<BYTE*>(&value); 451 BYTE* value_bytes = reinterpret_cast<BYTE*>(&value);
469 DWORD size = sizeof(value); 452 DWORD size = sizeof(value);
470 DWORD type = REG_DWORD; 453 DWORD type = REG_DWORD;
471 454
472 if (::RegOpenKeyEx(HKEY_LOCAL_MACHINE, kRegPathChromePolicy, 0, 455 if (::RegOpenKeyEx(HKEY_LOCAL_MACHINE, kRegPathChromePolicy, 0,
473 KEY_QUERY_VALUE, &key) == ERROR_SUCCESS) { 456 KEY_QUERY_VALUE, &key) == ERROR_SUCCESS) {
474 if (::RegQueryValueEx(key, kMetricsReportingEnabled, 0, &type, 457 if (::RegQueryValueEx(key, kMetricsReportingEnabled, 0, &type,
475 value_bytes, &size) == ERROR_SUCCESS) { 458 value_bytes, &size) == ERROR_SUCCESS) {
476 *metrics_is_enforced_by_policy = value != 0; 459 *metrics_is_enforced_by_policy = value != 0;
(...skipping 13 matching lines...) Expand all
490 } 473 }
491 474
492 return false; 475 return false;
493 } 476 }
494 477
495 void InitializeProcessType() { 478 void InitializeProcessType() {
496 assert(g_process_type == ProcessType::UNINITIALIZED); 479 assert(g_process_type == ProcessType::UNINITIALIZED);
497 typedef bool (*IsSandboxedProcessFunc)(); 480 typedef bool (*IsSandboxedProcessFunc)();
498 IsSandboxedProcessFunc is_sandboxed_process_func = 481 IsSandboxedProcessFunc is_sandboxed_process_func =
499 reinterpret_cast<IsSandboxedProcessFunc>( 482 reinterpret_cast<IsSandboxedProcessFunc>(
500 GetProcAddress(GetModuleHandle(NULL), "IsSandboxedProcess")); 483 GetProcAddress(GetModuleHandle(nullptr), "IsSandboxedProcess"));
501 if (is_sandboxed_process_func && is_sandboxed_process_func()) { 484 if (is_sandboxed_process_func && is_sandboxed_process_func()) {
502 g_process_type = ProcessType::NON_BROWSER_PROCESS; 485 g_process_type = ProcessType::NON_BROWSER_PROCESS;
503 return; 486 return;
504 } 487 }
505 488
506 // TODO(robertshield): Drop the command line check when we drop support for 489 // TODO(robertshield): Drop the command line check when we drop support for
507 // enabling chrome_elf in unsandboxed processes. 490 // enabling chrome_elf in unsandboxed processes.
508 const wchar_t* command_line = GetCommandLine(); 491 const wchar_t* command_line = GetCommandLine();
509 if (command_line && wcsstr(command_line, L"--type")) { 492 if (command_line && wcsstr(command_line, L"--type")) {
510 g_process_type = ProcessType::NON_BROWSER_PROCESS; 493 g_process_type = ProcessType::NON_BROWSER_PROCESS;
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after
568 // We have to make sure the user data dir exists on first run. See 551 // We have to make sure the user data dir exists on first run. See
569 // http://crbug.com/591504. 552 // http://crbug.com/591504.
570 if (!RecursiveDirectoryCreate(crash_dir->c_str())) 553 if (!RecursiveDirectoryCreate(crash_dir->c_str()))
571 return false; 554 return false;
572 crash_dir->append(L"\\Crashpad"); 555 crash_dir->append(L"\\Crashpad");
573 return true; 556 return true;
574 } 557 }
575 558
576 559
577 std::string GetEnvironmentString(const std::string& variable_name) { 560 std::string GetEnvironmentString(const std::string& variable_name) {
578 DWORD value_length = ::GetEnvironmentVariable( 561 DWORD value_length =
579 utf8_to_string16(variable_name).c_str(), NULL, 0); 562 ::GetEnvironmentVariable(UTF8ToUTF16(variable_name).c_str(), nullptr, 0);
580 if (value_length == 0) 563 if (value_length == 0)
581 return std::string(); 564 return std::string();
582 std::unique_ptr<wchar_t[]> value(new wchar_t[value_length]); 565 std::unique_ptr<wchar_t[]> value(new wchar_t[value_length]);
583 ::GetEnvironmentVariable(utf8_to_string16(variable_name).c_str(), 566 ::GetEnvironmentVariable(UTF8ToUTF16(variable_name).c_str(), value.get(),
584 value.get(), value_length); 567 value_length);
585 return utf16_to_utf8(value.get()); 568 return UTF16ToUTF8(value.get());
586 } 569 }
587 570
588 bool SetEnvironmentString(const std::string& variable_name, 571 bool SetEnvironmentString(const std::string& variable_name,
589 const std::string& new_value) { 572 const std::string& new_value) {
590 return !!SetEnvironmentVariable(utf8_to_string16(variable_name).c_str(), 573 return !!SetEnvironmentVariable(UTF8ToUTF16(variable_name).c_str(),
591 utf8_to_string16(new_value).c_str()); 574 UTF8ToUTF16(new_value).c_str());
592 } 575 }
593 576
594 bool HasEnvironmentVariable(const std::string& variable_name) { 577 bool HasEnvironmentVariable(const std::string& variable_name) {
595 return !!::GetEnvironmentVariable(utf8_to_string16(variable_name).c_str(), 578 return !!::GetEnvironmentVariable(UTF8ToUTF16(variable_name).c_str(), nullptr,
596 NULL, 0); 579 0);
597 } 580 }
598 581
599 bool GetExecutableVersionDetails(const base::string16& exe_path, 582 bool GetExecutableVersionDetails(const base::string16& exe_path,
600 base::string16* product_name, 583 base::string16* product_name,
601 base::string16* version, 584 base::string16* version,
602 base::string16* special_build, 585 base::string16* special_build,
603 base::string16* channel_name) { 586 base::string16* channel_name) {
604 assert(product_name); 587 assert(product_name);
605 assert(version); 588 assert(version);
606 assert(special_build); 589 assert(special_build);
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after
705 std::string GetGoogleUpdateVersion() { 688 std::string GetGoogleUpdateVersion() {
706 // TODO(ananta) 689 // TODO(ananta)
707 // Consider whether Chromium should connect to Google update to manage 690 // Consider whether Chromium should connect to Google update to manage
708 // updates. Should this be returning an empty string for Chromium builds?. 691 // updates. Should this be returning an empty string for Chromium builds?.
709 base::string16 update_version; 692 base::string16 update_version;
710 if (ReadKeyValueString(IsSystemInstall(GetCurrentProcessExePath().c_str()), 693 if (ReadKeyValueString(IsSystemInstall(GetCurrentProcessExePath().c_str()),
711 kRegPathGoogleUpdate, 694 kRegPathGoogleUpdate,
712 nullptr, 695 nullptr,
713 kRegGoogleUpdateVersion, 696 kRegGoogleUpdateVersion,
714 &update_version)) { 697 &update_version)) {
715 return utf16_to_utf8(update_version); 698 return UTF16ToUTF8(update_version);
716 } 699 }
717 return std::string(); 700 return std::string();
718 } 701 }
719 702
720 base::string16 GetChromeInstallSubDirectory() { 703 base::string16 GetChromeInstallSubDirectory() {
721 #if defined(GOOGLE_CHROME_BUILD) 704 #if defined(GOOGLE_CHROME_BUILD)
722 base::string16 result = kGoogleChromeInstallSubDir1; 705 base::string16 result = kGoogleChromeInstallSubDir1;
723 result += L"\\"; 706 result += L"\\";
724 result += kGoogleChromeInstallSubDir2; 707 result += kGoogleChromeInstallSubDir2;
725 if (IsSxSChrome(GetCurrentProcessExePath().c_str())) 708 if (IsSxSChrome(GetCurrentProcessExePath().c_str()))
(...skipping 10 matching lines...) Expand all
736 registry_path += kBrowserCrashDumpMetricsSubKey; 719 registry_path += kBrowserCrashDumpMetricsSubKey;
737 return registry_path; 720 return registry_path;
738 } 721 }
739 722
740 bool MatchPattern(const base::string16& source, 723 bool MatchPattern(const base::string16& source,
741 const base::string16& pattern) { 724 const base::string16& pattern) {
742 assert(pattern.find(L"**") == base::string16::npos); 725 assert(pattern.find(L"**") == base::string16::npos);
743 return MatchPatternImpl(source, pattern, 0, 0); 726 return MatchPatternImpl(source, pattern, 0, 0);
744 } 727 }
745 728
729 std::string UTF16ToUTF8(const base::string16& source) {
730 if (source.empty() ||
731 static_cast<int>(source.size()) > std::numeric_limits<int>::max()) {
732 return std::string();
733 }
734 int size = ::WideCharToMultiByte(CP_UTF8, 0, &source[0],
735 static_cast<int>(source.size()), nullptr, 0,
736 nullptr, nullptr);
737 std::string result(size, '\0');
738 if (::WideCharToMultiByte(CP_UTF8, 0, &source[0],
739 static_cast<int>(source.size()), &result[0], size,
740 nullptr, nullptr) != size) {
741 assert(false);
742 return std::string();
743 }
744 return result;
745 }
746
747 base::string16 UTF8ToUTF16(const std::string& source) {
748 if (source.empty() ||
749 static_cast<int>(source.size()) > std::numeric_limits<int>::max()) {
750 return base::string16();
751 }
752 int size = ::MultiByteToWideChar(CP_UTF8, 0, &source[0],
753 static_cast<int>(source.size()), nullptr, 0);
754 base::string16 result(size, L'\0');
755 if (::MultiByteToWideChar(CP_UTF8, 0, &source[0],
756 static_cast<int>(source.size()), &result[0],
757 size) != size) {
758 assert(false);
759 return base::string16();
760 }
761 return result;
762 }
763
764 std::vector<std::string> TokenizeString(const std::string& str,
765 char delimiter,
766 bool trim_spaces) {
767 std::vector<std::string> tokens;
768 std::istringstream buffer(str);
769 for (std::string token; std::getline(buffer, token, delimiter);) {
770 if (trim_spaces)
771 Trim(&token);
772 tokens.push_back(token);
773 }
774 return tokens;
775 }
776
777 bool CompareVersionStrings(const std::string& version1,
778 const std::string& version2,
779 int* result) {
780 if (version1.empty() || version2.empty())
781 return false;
782
783 // Tokenize both version strings with "." as the separator. If either of
784 // the returned token lists are empty then bail.
785 std::vector<std::string> version1_components =
786 TokenizeString(version1, '.', false);
787 if (version1_components.empty())
788 return false;
789
790 std::vector<std::string> version2_components =
791 TokenizeString(version2, '.', false);
792 if (version2_components.empty())
793 return false;
794
795 // You may have less tokens in either string. Use the minimum of the number
796 // of tokens as the initial count.
797 const size_t count =
798 std::min(version1_components.size(), version2_components.size());
799 for (size_t i = 0; i < count; ++i) {
800 // If either of the version components don't contain valid numeric digits
801 // bail.
802 if (!IsValidNumber(version1_components[i]) ||
803 !IsValidNumber(version2_components[i])) {
804 return false;
805 }
806
807 int version1_component = std::stoi(version1_components[i]);
808 int version2_component = std::stoi(version2_components[i]);
809
810 if (version1_component > version2_component) {
811 *result = 1;
812 return true;
813 }
814
815 if (version1_component < version2_component) {
816 *result = -1;
817 return true;
818 }
819 }
820
821 // Handle remaining tokens. Here if we have non zero tokens remaining in the
822 // version 1 list then it means that the version1 string is larger. If the
823 // version 1 token list has tokens left, then if either of these tokens is
824 // greater than 0 then it means that the version1 string is smaller than the
825 // version2 string.
826 if (version1_components.size() > version2_components.size()) {
827 for (size_t i = count; i < version1_components.size(); ++i) {
828 // If the version components don't contain valid numeric digits bail.
829 if (!IsValidNumber(version1_components[i]))
830 return false;
831
832 if (std::stoi(version1_components[i]) > 0) {
833 *result = 1;
834 return true;
835 }
836 }
837 } else if (version1_components.size() < version2_components.size()) {
838 for (size_t i = count; i < version2_components.size(); ++i) {
839 // If the version components don't contain valid numeric digits bail.
840 if (!IsValidNumber(version2_components[i]))
841 return false;
842
843 if (std::stoi(version2_components[i]) > 0) {
844 *result = -1;
845 return true;
846 }
847 }
848 }
849 // Here it means that both versions are equal.
850 *result = 0;
851 return true;
852 }
853
746 } // namespace install_static 854 } // namespace install_static
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698