1// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chrome/common/extensions/extension_resource.h"
6
7#include "base/file_util.h"
8#include "base/logging.h"
9#include "base/threading/thread_restrictions.h"
10
11ExtensionResource::ExtensionResource() {
12}
13
14ExtensionResource::ExtensionResource(const std::string& extension_id,
15                                     const FilePath& extension_root,
16                                     const FilePath& relative_path)
17    : extension_id_(extension_id),
18      extension_root_(extension_root),
19      relative_path_(relative_path) {
20}
21
22ExtensionResource::~ExtensionResource() {}
23
24const FilePath& ExtensionResource::GetFilePath() const {
25  if (extension_root_.empty() || relative_path_.empty()) {
26    DCHECK(full_resource_path_.empty());
27    return full_resource_path_;
28  }
29
30  // We've already checked, just return last value.
31  if (!full_resource_path_.empty())
32    return full_resource_path_;
33
34  full_resource_path_ =
35      GetFilePath(extension_root_, relative_path_);
36  return full_resource_path_;
37}
38
39// static
40FilePath ExtensionResource::GetFilePath(
41    const FilePath& extension_root, const FilePath& relative_path) {
42  // We need to resolve the parent references in the extension_root
43  // path on its own because IsParent doesn't like parent references.
44  FilePath clean_extension_root(extension_root);
45  if (!file_util::AbsolutePath(&clean_extension_root))
46    return FilePath();
47
48  FilePath full_path = clean_extension_root.Append(relative_path);
49
50  // We must resolve the absolute path of the combined path when
51  // the relative path contains references to a parent folder (i.e., '..').
52  // We also check if the path exists because the posix version of AbsolutePath
53  // will fail if the path doesn't exist, and we want the same behavior on
54  // Windows... So until the posix and Windows version of AbsolutePath are
55  // unified, we need an extra call to PathExists, unfortunately.
56  // TODO(mad): Fix this once AbsolutePath is unified.
57  if (file_util::AbsolutePath(&full_path) &&
58      file_util::PathExists(full_path) &&
59      clean_extension_root.IsParent(full_path)) {
60    return full_path;
61  }
62
63  return FilePath();
64}
65
66// Unit-testing helpers.
67FilePath::StringType ExtensionResource::NormalizeSeperators(
68    const FilePath::StringType& path) const {
69#if defined(FILE_PATH_USES_WIN_SEPARATORS)
70  FilePath::StringType win_path = path;
71  for (size_t i = 0; i < win_path.length(); i++) {
72    if (FilePath::IsSeparator(win_path[i]))
73      win_path[i] = FilePath::kSeparators[0];
74  }
75  return win_path;
76#else
77  return path;
78#endif  // FILE_PATH_USES_WIN_SEPARATORS
79}
80
81bool ExtensionResource::ComparePathWithDefault(const FilePath& path) const {
82  // Make sure we have a cached value to test against...
83  if (full_resource_path_.empty())
84    GetFilePath();
85  if (NormalizeSeperators(path.value()) ==
86    NormalizeSeperators(full_resource_path_.value())) {
87    return true;
88  } else {
89    return false;
90  }
91}
92