OLD | NEW |
---|---|
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 <stdlib.h> | 9 #include <stdlib.h> |
10 #include <string.h> | 10 #include <string.h> |
(...skipping 563 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
574 bool trim_spaces) { | 574 bool trim_spaces) { |
575 return TokenizeStringT<std::string>(str, delimiter, trim_spaces); | 575 return TokenizeStringT<std::string>(str, delimiter, trim_spaces); |
576 } | 576 } |
577 | 577 |
578 std::vector<std::wstring> TokenizeString16(const std::wstring& str, | 578 std::vector<std::wstring> TokenizeString16(const std::wstring& str, |
579 wchar_t delimiter, | 579 wchar_t delimiter, |
580 bool trim_spaces) { | 580 bool trim_spaces) { |
581 return TokenizeStringT<std::wstring>(str, delimiter, trim_spaces); | 581 return TokenizeStringT<std::wstring>(str, delimiter, trim_spaces); |
582 } | 582 } |
583 | 583 |
584 std::vector<std::wstring> TokenizeCommandLineToArray( | |
585 const std::wstring& command_line) { | |
586 // This is baroquely complex to do properly, see e.g. | |
587 // https://blogs.msdn.microsoft.com/oldnewthing/20100917-00/?p=12833 | |
588 // http://www.windowsinspired.com/how-a-windows-programs-splits-its-command-li ne-into-individual-arguments/ | |
589 // and many others. We cannot use CommandLineToArgvW() in chrome_elf, because | |
590 // it's in shell32.dll. Previously, __wgetmainargs() in the CRT was available, | |
591 // and it's still documented for VS 2015 at | |
592 // https://msdn.microsoft.com/en-us/library/ff770599.aspx but unfortunately, | |
593 // isn't actually available. | |
594 // | |
595 // This parsing matches CommandLineToArgvW()s for arguments, rather than the | |
596 // CRTs. These are different only in the most obscure of cases and will not | |
597 // matter in any practical situation. See the windowsinspired.com post above | |
598 // for details. | |
599 // | |
600 // TODO(scottmg): argv[0] normally has special handling. We should likely do | |
601 // that. | |
602 | |
603 enum class SpecialChars { | |
grt (UTC plus 2)
2016/12/01 09:07:13
i think some comments in here are worthwhile. i've
scottmg
2016/12/01 19:04:21
Done.
| |
604 kInterpret, | |
grt (UTC plus 2)
2016/12/01 09:07:13
// Space or tab, if encountered, delimit a break b
scottmg
2016/12/01 19:04:21
Done.
| |
605 kIgnore, | |
grt (UTC plus 2)
2016/12/01 09:07:12
// Space or tab, if encountered, are part of the c
scottmg
2016/12/01 19:04:21
Done.
| |
606 } state; | |
607 | |
608 std::vector<std::wstring> result; | |
609 std::wstring token; | |
610 | |
611 const wchar_t* p = command_line.c_str(); | |
612 // This loops the entire string, with a subloop for each argument. | |
613 for (;;) { | |
614 // Advance past leading whitespace (only space and tab are handled). | |
615 p += wcsspn(p, L" \t"); | |
616 | |
617 // End of arguments. | |
618 if (p[0] == 0) { | |
619 if (!token.empty()) | |
620 result.push_back(token); | |
621 break; | |
622 } | |
623 | |
624 state = SpecialChars::kInterpret; | |
625 | |
626 // Scan an argument. | |
627 for (;;) { | |
628 // Count and advance past leading backslashes. | |
grt (UTC plus 2)
2016/12/01 09:07:12
nit: since this counts all backslashes, not only l
scottmg
2016/12/01 19:04:21
Done.
| |
629 int num_backslashes = 0; | |
630 while (p[0] == L'\\') { | |
631 ++p; | |
632 ++num_backslashes; | |
633 } | |
634 | |
635 if (p[0] == L'"') { | |
636 for (int i = 1; i < num_backslashes; i += 2) | |
grt (UTC plus 2)
2016/12/01 09:07:13
tiny nit: a single append will be more performant
scottmg
2016/12/01 19:04:22
Done. (num_backslashes / 2) though.
grt (UTC plus 2)
2016/12/02 10:18:03
Oops. Cool.
| |
637 token += L'\\'; | |
638 | |
639 if (num_backslashes % 2 == 1) { | |
640 token += L'"'; | |
grt (UTC plus 2)
2016/12/01 09:07:13
// An odd number of backslashes followed by a quot
scottmg
2016/12/01 19:04:21
Done.
| |
641 } else if (p[1] == L'"' && state == SpecialChars::kIgnore) { | |
grt (UTC plus 2)
2016/12/01 09:07:13
will this not be an OOB read for a string that end
scottmg
2016/12/01 19:04:21
I think it's safe, because .c_str() is null termin
| |
642 ++p; | |
grt (UTC plus 2)
2016/12/01 09:07:12
// Special case for consecutive double quotes whil
scottmg
2016/12/01 19:04:22
Done.
| |
643 token += L'"'; | |
644 state = SpecialChars::kInterpret; | |
645 } else { | |
646 state = state == SpecialChars::kInterpret ? SpecialChars::kIgnore | |
647 : SpecialChars::kInterpret; | |
648 } | |
649 } else { | |
650 for (int i = 0; i < num_backslashes; ++i) | |
grt (UTC plus 2)
2016/12/01 09:07:13
// Emit backslashes that do not precede a double q
scottmg
2016/12/01 19:04:22
Done.
| |
651 token += L'\\'; | |
652 if (p[0] == 0 || | |
653 (wcschr(L" \t", p[0]) && state == SpecialChars::kInterpret)) { | |
grt (UTC plus 2)
2016/12/01 09:07:12
nit: swap these two so that the cheap condition is
scottmg
2016/12/01 19:04:21
Done.
| |
654 result.push_back(token); | |
655 token.clear(); | |
656 break; | |
657 } else { | |
grt (UTC plus 2)
2016/12/01 09:07:12
nit: omit "else" since the "if" branch breaks for
scottmg
2016/12/01 19:04:21
Done.
| |
658 token += *p; | |
659 } | |
660 } | |
661 | |
662 ++p; | |
663 } | |
664 } | |
665 | |
666 return result; | |
667 } | |
668 | |
584 std::wstring GetSwitchValueFromCommandLine(const std::wstring& command_line, | 669 std::wstring GetSwitchValueFromCommandLine(const std::wstring& command_line, |
585 const std::wstring& switch_name) { | 670 const std::wstring& switch_name) { |
586 assert(!command_line.empty()); | 671 assert(!command_line.empty()); |
587 assert(!switch_name.empty()); | 672 assert(!switch_name.empty()); |
588 | 673 |
589 std::wstring command_line_copy = command_line; | 674 std::vector<std::wstring> as_array = TokenizeCommandLineToArray(command_line); |
590 // Remove leading and trailing spaces. | 675 std::wstring switch_with_equal = L"--" + switch_name + L"="; |
591 TrimT<std::wstring>(&command_line_copy); | 676 for (size_t i = 1; i < as_array.size(); ++i) { |
grt (UTC plus 2)
2016/12/01 09:07:12
nit
for (const std::wstring& arg : as_array) {
scottmg
2016/12/01 19:04:22
I'd prefer that, but is there an easy way to do th
grt (UTC plus 2)
2016/12/02 10:18:03
oh, 1, duh. apologies
| |
677 const std::wstring& arg = as_array[i]; | |
678 if (arg.compare(0, switch_with_equal.size(), switch_with_equal) == 0) { | |
grt (UTC plus 2)
2016/12/01 09:07:13
nit: omit braces
scottmg
2016/12/01 19:04:22
Heh, done. I forgot to switch from mark@ back to g
| |
679 return arg.substr(switch_with_equal.size()); | |
680 } | |
681 } | |
592 | 682 |
593 // Find the switch in the command line. If we don't find the switch, return | 683 return std::wstring(); |
594 // an empty string. | |
595 std::wstring switch_token = L"--"; | |
596 switch_token += switch_name; | |
597 switch_token += L"="; | |
598 size_t switch_offset = command_line_copy.find(switch_token); | |
599 if (switch_offset == std::string::npos) | |
600 return std::wstring(); | |
601 | |
602 // The format is "--<switch name>=blah". Look for a space after the | |
603 // "--<switch name>=" string. If we don't find a space assume that the switch | |
604 // value ends at the end of the command line. | |
605 size_t switch_value_start_offset = switch_offset + switch_token.length(); | |
606 if (std::wstring(kWhiteSpaces16).find( | |
607 command_line_copy[switch_value_start_offset]) != std::wstring::npos) { | |
608 switch_value_start_offset = command_line_copy.find_first_not_of( | |
609 GetWhiteSpacesForType<std::wstring>(), switch_value_start_offset); | |
610 if (switch_value_start_offset == std::wstring::npos) | |
611 return std::wstring(); | |
612 } | |
613 size_t switch_value_end_offset = | |
614 command_line_copy.find_first_of(GetWhiteSpacesForType<std::wstring>(), | |
615 switch_value_start_offset); | |
616 if (switch_value_end_offset == std::wstring::npos) | |
617 switch_value_end_offset = command_line_copy.length(); | |
618 | |
619 std::wstring switch_value = command_line_copy.substr( | |
620 switch_value_start_offset, | |
621 switch_value_end_offset - (switch_offset + switch_token.length())); | |
622 TrimT<std::wstring>(&switch_value); | |
623 return switch_value; | |
624 } | 684 } |
625 | 685 |
626 bool RecursiveDirectoryCreate(const std::wstring& full_path) { | 686 bool RecursiveDirectoryCreate(const std::wstring& full_path) { |
627 // If the path exists, we've succeeded if it's a directory, failed otherwise. | 687 // If the path exists, we've succeeded if it's a directory, failed otherwise. |
628 const wchar_t* full_path_str = full_path.c_str(); | 688 const wchar_t* full_path_str = full_path.c_str(); |
629 DWORD file_attributes = ::GetFileAttributes(full_path_str); | 689 DWORD file_attributes = ::GetFileAttributes(full_path_str); |
630 if (file_attributes != INVALID_FILE_ATTRIBUTES) { | 690 if (file_attributes != INVALID_FILE_ATTRIBUTES) { |
631 if ((file_attributes & FILE_ATTRIBUTE_DIRECTORY) != 0) { | 691 if ((file_attributes & FILE_ATTRIBUTE_DIRECTORY) != 0) { |
632 Trace(L"%hs( %ls directory exists )\n", __func__, full_path_str); | 692 Trace(L"%hs( %ls directory exists )\n", __func__, full_path_str); |
633 return true; | 693 return true; |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
683 case ChannelStrategy::ADDITIONAL_PARAMETERS: | 743 case ChannelStrategy::ADDITIONAL_PARAMETERS: |
684 return ChannelFromAdditionalParameters(mode, system_level, multi_install); | 744 return ChannelFromAdditionalParameters(mode, system_level, multi_install); |
685 case ChannelStrategy::FIXED: | 745 case ChannelStrategy::FIXED: |
686 return mode.default_channel_name; | 746 return mode.default_channel_name; |
687 } | 747 } |
688 | 748 |
689 return std::wstring(); | 749 return std::wstring(); |
690 } | 750 } |
691 | 751 |
692 } // namespace install_static | 752 } // namespace install_static |
OLD | NEW |