|  | // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | #include "tools/gn/source_dir.h" | 
|  |  | 
|  | #include <string> | 
|  |  | 
|  | #include "base/logging.h" | 
|  | #include "tools/gn/filesystem_utils.h" | 
|  | #include "tools/gn/source_file.h" | 
|  | #include "util/build_config.h" | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | void AssertValueSourceDirString(const std::string& s) { | 
|  | if (!s.empty()) { | 
|  | #if defined(OS_WIN) | 
|  | DCHECK(s[0] == '/' || | 
|  | (s.size() > 2 && s[0] != '/' && s[1] == ':' && IsSlash(s[2]))); | 
|  | #else | 
|  | DCHECK(s[0] == '/'); | 
|  | #endif | 
|  | DCHECK(EndsWithSlash(s)) << s; | 
|  | } | 
|  | } | 
|  |  | 
|  | // Validates input value (input_value) and sets proper error message. | 
|  | // Note: Parameter blame_input is used only for generating error message. | 
|  | template <typename StringType> | 
|  | bool ValidateResolveInput(bool as_file, | 
|  | const Value& blame_input_value, | 
|  | const StringType& input_value, | 
|  | Err* err) { | 
|  | if (as_file) { | 
|  | // It's an error to resolve an empty string or one that is a directory | 
|  | // (indicated by a trailing slash) because this is the function that expects | 
|  | // to return a file. | 
|  | if (input_value.empty()) { | 
|  | *err = Err(blame_input_value, "Empty file path.", | 
|  | "You can't use empty strings as file paths."); | 
|  | return false; | 
|  | } else if (input_value[input_value.size() - 1] == '/') { | 
|  | std::string help = "You specified the path\n  "; | 
|  | help.append(std::string(input_value)); | 
|  | help.append( | 
|  | "\nand it ends in a slash, indicating you think it's a directory." | 
|  | "\nBut here you're supposed to be listing a file."); | 
|  | *err = Err(blame_input_value, "File path ends in a slash.", help); | 
|  | return false; | 
|  | } | 
|  | } else if (input_value.empty()) { | 
|  | *err = Err(blame_input_value, "Empty directory path.", | 
|  | "You can't use empty strings as directories."); | 
|  | return false; | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | }  // namespace | 
|  |  | 
|  | SourceDir::SourceDir(const std::string& s) : value_(s) { | 
|  | if (!EndsWithSlash(value_)) | 
|  | value_.push_back('/'); | 
|  | AssertValueSourceDirString(value_); | 
|  | } | 
|  |  | 
|  | SourceDir::SourceDir(std::string&& s) : value_(std::move(s)) { | 
|  | if (!EndsWithSlash(value_)) | 
|  | value_.push_back('/'); | 
|  | AssertValueSourceDirString(value_); | 
|  | } | 
|  |  | 
|  | template <typename StringType> | 
|  | std::string SourceDir::ResolveRelativeAs( | 
|  | bool as_file, | 
|  | const Value& blame_input_value, | 
|  | const StringType& input_value, | 
|  | Err* err, | 
|  | const std::string_view& source_root) const { | 
|  | if (!ValidateResolveInput<StringType>(as_file, blame_input_value, input_value, | 
|  | err)) { | 
|  | return std::string(); | 
|  | } | 
|  | return ResolveRelative(input_value, value_, as_file, source_root); | 
|  | } | 
|  |  | 
|  | SourceFile SourceDir::ResolveRelativeFile( | 
|  | const Value& p, | 
|  | Err* err, | 
|  | const std::string_view& source_root) const { | 
|  | SourceFile ret; | 
|  |  | 
|  | if (!p.VerifyTypeIs(Value::STRING, err)) | 
|  | return ret; | 
|  |  | 
|  | const std::string& input_string = p.string_value(); | 
|  | if (!ValidateResolveInput<std::string>(true, p, input_string, err)) | 
|  | return ret; | 
|  |  | 
|  | ret.SetValue(ResolveRelative(input_string, value_, true, source_root)); | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | std::string SourceDir::ResolveRelativeAs(bool as_file, | 
|  | const Value& v, | 
|  | Err* err, | 
|  | const std::string_view& source_root, | 
|  | const std::string* v_value) const { | 
|  | if (!v.VerifyTypeIs(Value::STRING, err)) | 
|  | return std::string(); | 
|  |  | 
|  | if (!v_value) { | 
|  | v_value = &v.string_value(); | 
|  | } | 
|  | std::string result = | 
|  | ResolveRelativeAs(as_file, v, *v_value, err, source_root); | 
|  | if (!as_file) | 
|  | AssertValueSourceDirString(result); | 
|  | return result; | 
|  | } | 
|  |  | 
|  | SourceDir SourceDir::ResolveRelativeDir( | 
|  | const Value& v, | 
|  | Err* err, | 
|  | const std::string_view& source_root) const { | 
|  | if (!v.VerifyTypeIs(Value::STRING, err)) | 
|  | return SourceDir(); | 
|  |  | 
|  | return ResolveRelativeDir<std::string>(v, v.string_value(), err, source_root); | 
|  | } | 
|  |  | 
|  | base::FilePath SourceDir::Resolve(const base::FilePath& source_root) const { | 
|  | return ResolvePath(value_, false, source_root); | 
|  | } | 
|  |  | 
|  | // Explicit template instantiation | 
|  | template std::string SourceDir::ResolveRelativeAs( | 
|  | bool as_file, | 
|  | const Value& blame_input_value, | 
|  | const std::string& input_value, | 
|  | Err* err, | 
|  | const std::string_view& source_root) const; | 
|  |  | 
|  | template std::string SourceDir::ResolveRelativeAs( | 
|  | bool as_file, | 
|  | const Value& blame_input_value, | 
|  | const std::string_view& input_value, | 
|  | Err* err, | 
|  | const std::string_view& source_root) const; |