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

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: Fix windows gn builder redness Created 4 years, 7 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 227 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",
(...skipping 109 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 const char kWhiteSpaces[] = " \t\n\r\f\v";
grt (UTC plus 2) 2016/05/27 14:13:20 nit: constexpr
ananta 2016/05/27 20:05:25 Done.
392
393 // Trim whitespaces from left.
394 void ltrim(std::string* str) {
395 str->erase(0, str->find_first_not_of(kWhiteSpaces));
396 }
397
398 // Trim whitespaces from right
399 void rtrim(std::string* str) {
400 str->erase(str->find_last_not_of(kWhiteSpaces) + 1);
401 }
402
403 // Trim whitespaces from left & right
404 void trim(std::string* str) {
scottmg 2016/05/27 17:27:22 trim -> Trim
ananta 2016/05/27 20:05:25 Done.
405 rtrim(str);
scottmg 2016/05/27 17:27:22 Seems like over-functioning since ltrim() and rtri
ananta 2016/05/27 20:05:25 Done.
406 ltrim(str);
407 }
408
409 bool is_valid_number(const std::string &str) {
scottmg 2016/05/27 17:27:22 IsValidNumber
ananta 2016/05/27 20:05:25 Done.
410 return std::all_of(str.begin(), str.end(), ::isdigit);
grt (UTC plus 2) 2016/05/27 14:13:20 as implemented, this will return true if std.empty
ananta 2016/05/27 20:05:25 Done.
411 }
412
422 } // namespace 413 } // namespace
423 414
424 bool IsSxSChrome(const wchar_t* exe_path) { 415 bool IsSxSChrome(const wchar_t* exe_path) {
425 return wcsstr(exe_path, L"Chrome SxS\\Application") != NULL; 416 return wcsstr(exe_path, L"Chrome SxS\\Application") != NULL;
426 } 417 }
427 418
428 bool IsSystemInstall(const wchar_t* exe_path) { 419 bool IsSystemInstall(const wchar_t* exe_path) {
429 wchar_t program_dir[MAX_PATH] = {}; 420 wchar_t program_dir[MAX_PATH] = {};
430 DWORD ret = ::GetEnvironmentVariable(L"PROGRAMFILES", program_dir, 421 DWORD ret = ::GetEnvironmentVariable(L"PROGRAMFILES", program_dir,
431 arraysize(program_dir)); 422 arraysize(program_dir));
(...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after
569 // http://crbug.com/591504. 560 // http://crbug.com/591504.
570 if (!RecursiveDirectoryCreate(crash_dir->c_str())) 561 if (!RecursiveDirectoryCreate(crash_dir->c_str()))
571 return false; 562 return false;
572 crash_dir->append(L"\\Crashpad"); 563 crash_dir->append(L"\\Crashpad");
573 return true; 564 return true;
574 } 565 }
575 566
576 567
577 std::string GetEnvironmentString(const std::string& variable_name) { 568 std::string GetEnvironmentString(const std::string& variable_name) {
578 DWORD value_length = ::GetEnvironmentVariable( 569 DWORD value_length = ::GetEnvironmentVariable(
579 utf8_to_string16(variable_name).c_str(), NULL, 0); 570 utf8_to_utf16(variable_name).c_str(), NULL, 0);
580 if (value_length == 0) 571 if (value_length == 0)
581 return std::string(); 572 return std::string();
582 std::unique_ptr<wchar_t[]> value(new wchar_t[value_length]); 573 std::unique_ptr<wchar_t[]> value(new wchar_t[value_length]);
583 ::GetEnvironmentVariable(utf8_to_string16(variable_name).c_str(), 574 ::GetEnvironmentVariable(utf8_to_utf16(variable_name).c_str(),
584 value.get(), value_length); 575 value.get(), value_length);
585 return utf16_to_utf8(value.get()); 576 return utf16_to_utf8(value.get());
586 } 577 }
587 578
588 bool SetEnvironmentString(const std::string& variable_name, 579 bool SetEnvironmentString(const std::string& variable_name,
589 const std::string& new_value) { 580 const std::string& new_value) {
590 return !!SetEnvironmentVariable(utf8_to_string16(variable_name).c_str(), 581 return !!SetEnvironmentVariable(utf8_to_utf16(variable_name).c_str(),
591 utf8_to_string16(new_value).c_str()); 582 utf8_to_utf16(new_value).c_str());
592 } 583 }
593 584
594 bool HasEnvironmentVariable(const std::string& variable_name) { 585 bool HasEnvironmentVariable(const std::string& variable_name) {
595 return !!::GetEnvironmentVariable(utf8_to_string16(variable_name).c_str(), 586 return !!::GetEnvironmentVariable(utf8_to_utf16(variable_name).c_str(),
596 NULL, 0); 587 NULL, 0);
597 } 588 }
598 589
599 bool GetExecutableVersionDetails(const base::string16& exe_path, 590 bool GetExecutableVersionDetails(const base::string16& exe_path,
600 base::string16* product_name, 591 base::string16* product_name,
601 base::string16* version, 592 base::string16* version,
602 base::string16* special_build, 593 base::string16* special_build,
603 base::string16* channel_name) { 594 base::string16* channel_name) {
604 assert(product_name); 595 assert(product_name);
605 assert(version); 596 assert(version);
(...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after
736 registry_path += kBrowserCrashDumpMetricsSubKey; 727 registry_path += kBrowserCrashDumpMetricsSubKey;
737 return registry_path; 728 return registry_path;
738 } 729 }
739 730
740 bool MatchPattern(const base::string16& source, 731 bool MatchPattern(const base::string16& source,
741 const base::string16& pattern) { 732 const base::string16& pattern) {
742 assert(pattern.find(L"**") == base::string16::npos); 733 assert(pattern.find(L"**") == base::string16::npos);
743 return MatchPatternImpl(source, pattern, 0, 0); 734 return MatchPatternImpl(source, pattern, 0, 0);
744 } 735 }
745 736
737 std::string utf16_to_utf8(const base::string16 &source) {
grt (UTC plus 2) 2016/05/27 14:13:20 nit: & before space. please use "git cl format" t
ananta 2016/05/27 20:05:25 Yeah. I had done that. It seems every time I copy
738 if (source.empty())
grt (UTC plus 2) 2016/05/27 14:13:20 || source.size() > std::numeric_limits<int>::max()
ananta 2016/05/27 20:05:25 Done.
739 return std::string();
740 int size = ::WideCharToMultiByte(CP_UTF8, 0, &source[0],
741 static_cast<int>(source.size()), nullptr, 0, nullptr, nullptr);
742 std::string result(size, '\0');
743 if (::WideCharToMultiByte(CP_UTF8, 0, &source[0],
744 static_cast<int>(source.size()), &result[0], size, nullptr,
745 nullptr) != size) {
746 assert(false);
747 return std::string();
748 }
749 return result;
750 }
751
752 base::string16 utf8_to_utf16(const std::string &source) {
753 if (source.empty())
grt (UTC plus 2) 2016/05/27 14:13:20 || source.size() > std::numeric_limits<int>::max()
ananta 2016/05/27 20:05:25 Done.
754 return base::string16();
755 int size = ::MultiByteToWideChar(CP_UTF8, 0, &source[0],
756 static_cast<int>(source.size()), nullptr, 0);
757 base::string16 result(size, L'\0');
758 if (::MultiByteToWideChar(CP_UTF8, 0, &source[0],
759 static_cast<int>(source.size()), &result[0], size) != size) {
760 assert(false);
761 return base::string16();
762 }
763 return result;
764 }
765
766 std::vector<std::string> TokenizeString(const std::string& str,
767 const char delimiter,
grt (UTC plus 2) 2016/05/27 14:13:20 no const
ananta 2016/05/27 20:05:25 Done.
768 bool trim_spaces) {
scottmg 2016/05/27 17:27:22 I only see trim_spaces=false calls other than in t
ananta 2016/05/27 20:05:25 Prefer to leave it as an argument. Just in case we
769 std::vector<std::string> tokens;
770 std::istringstream buffer(str);
771 for (std::string token; std::getline(buffer, token, delimiter); ) {
772 if (trim_spaces)
773 trim(&token);
774 tokens.push_back(token);
775 }
776 return tokens;
777 }
778
779 bool CompareVersionStrings(const std::string& version1,
780 const std::string& version2,
781 int* result) {
782 if (version1.empty() || version2.empty())
783 return false;
784
785 // Tokenize both version strings with "." as the separator. If either of
786 // the returned token lists are empty then bail.
787 std::vector<std::string> version1_components =
788 install_static::TokenizeString(version1, '.', false);
grt (UTC plus 2) 2016/05/27 14:13:20 omit "install_static::"
ananta 2016/05/27 20:05:25 Done.
789 if (version1_components.empty())
790 return false;
791
792 std::vector<std::string> version2_components =
793 install_static::TokenizeString(version2, '.', false);
794 if (version2_components.empty())
795 return false;
796
797 // You may have less tokens in either string. Use the minimum of the number
798 // of tokens as the initial count.
799 const size_t count = std::min(version1_components.size(),
scottmg 2016/05/27 17:27:22 nit; weird line break
ananta 2016/05/27 20:05:25 Done.
800 version2_components.size());
801 for (size_t i = 0; i < count; ++i) {
802 // If either of the version components don't contain valid numeric digits
803 // bail.
804 if (!is_valid_number(version1_components[i]) ||
805 !is_valid_number(version2_components[i])) {
806 return false;
807 }
808
809 int version1_component = std::stoi(version1_components[i]);
scottmg 2016/05/27 17:27:22 Ooh, this defaults to base=10, not =0, woohoo!
ananta 2016/05/27 20:05:25 Yeah
810 int version2_component = std::stoi(version2_components[i]);
811
812 if (version1_component > version2_component) {
813 *result = 1;
814 return true;
815 }
816
817 if (version1_component < version2_component) {
818 *result = -1;
819 return true;
820 }
821 }
822
823 // Handle remaining tokens. Here if we have non zero tokens remaining in the
824 // version 1 list then it means that the version1 string is larger. If the
825 // version 1 token list has tokens left, then if either of these tokens is
826 // greater than 0 then it means that the version1 string is smaller than the
827 // version2 string.
828 if (version1_components.size() > version2_components.size()) {
829 for (size_t i = count; i < version1_components.size(); ++i) {
830 // If the version components don't contain valid numeric digits bail.
831 if (!is_valid_number(version1_components[i]))
832 return false;
833
834 if (std::stoi(version1_components[i]) > 0) {
835 *result = 1;
836 return true;
837 }
838 }
839 } else if (version1_components.size() < version2_components.size()) {
840 for (size_t i = count; i < version2_components.size(); ++i) {
841 // If the version components don't contain valid numeric digits bail.
842 if (!is_valid_number(version2_components[i]))
843 return false;
844
845 if (std::stoi(version2_components[i]) > 0) {
846 *result = -1;
847 return true;
848 }
849 }
850 }
851 // Here it means that both versions are equal.
852 *result = 0;
853 return true;
854 }
855
746 } // namespace install_static 856 } // namespace install_static
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698