summaryrefslogtreecommitdiff
path: root/chromium/components/resource_provider/file_utils.cc
blob: b8063da1c7221848428295deae3f5b293b9c269b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
// Copyright 2015 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 "components/resource_provider/file_utils.h"

#include <stddef.h>

#include "base/files/file_path.h"
#include "base/path_service.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
#include "build/build_config.h"

namespace resource_provider {
namespace {

bool IsPathNameValid(const std::string& name) {
  if (name.empty() || name == "." || name == "..")
    return false;

  for (auto c : name) {
    if (!base::IsAsciiAlpha(c) && !base::IsAsciiDigit(c) &&
        c != '_' && c != '.')
      return false;
  }
  return true;
}

}  // namespace

base::FilePath GetPathForApplicationName(const std::string& application_name) {
  std::string path = application_name;
  const bool is_mojo =
      base::StartsWith(path, "mojo:", base::CompareCase::INSENSITIVE_ASCII);
  const bool is_exe =
      !is_mojo &&
      base::StartsWith(path, "exe:", base::CompareCase::INSENSITIVE_ASCII);
  if (!is_mojo && !is_exe)
    return base::FilePath();
  if (path.find('.') != std::string::npos)
    return base::FilePath();
  if (is_mojo)
    path.erase(path.begin(), path.begin() + 5);
  else
    path.erase(path.begin(), path.begin() + 4);
  base::TrimString(path, "/", &path);
  size_t end_of_name = path.find('/');
  if (end_of_name != std::string::npos)
    path.erase(path.begin() + end_of_name, path.end());

  // TODO(beng): I'm adding this because there is a collision between the
  //             executable name in the exe dir and the resource package dir on
  //             non-Windows systems. Arbitrary exes should probably load their
  //             resources themselves rather than use resource provider.
  if (is_exe)
    path += "_res";

  if (!IsPathNameValid(path))
    return base::FilePath();

  base::FilePath base_path;
#if defined(OS_ANDROID)
  PathService::Get(base::DIR_ANDROID_APP_DATA, &base_path);
  // |base_path| on android has an additional path, need to go up a level to get
  // at other apps resources.
  base_path = base_path.DirName();
  base_path = base_path.AppendASCII("app_cached_apps");
#else
  PathService::Get(base::DIR_EXE, &base_path);
#endif
  // TODO(beng): this won't handle user-specific components.
  return base_path.AppendASCII("Mojo Applications").AppendASCII(path).
      AppendASCII("resources");
}

base::FilePath GetPathForResourceNamed(const base::FilePath& app_path,
                                       const std::string& resource_path) {
  CHECK(!app_path.empty());

  if (resource_path.empty() || resource_path[0] == '/' ||
      resource_path[resource_path.size() - 1] == '/' ||
      resource_path.find("//") != std::string::npos)
    return base::FilePath();

  std::vector<std::string> path_components = base::SplitString(
      resource_path, "/", base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
  if (path_components.empty())
    return base::FilePath();

  base::FilePath result(app_path);
  for (const auto& path_component : path_components) {
    if (!IsPathNameValid(path_component))
      return base::FilePath();
    result = result.AppendASCII(path_component);
  }
  return result;
}

}  // namespace resource_provider