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

Side by Side Diff: chrome/browser/chromeos/arc/fileapi/arc_documents_provider_document.cc

Issue 2574173002: mediaview: Implement ArcDocumentsProviderRoot. (Closed)
Patch Set: Rebased to ToT. Created 4 years 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
(Empty)
1 // Copyright 2016 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/browser/chromeos/arc/fileapi/arc_documents_provider_document.h"
6
7 #include <set>
8
9 #include "base/memory/ptr_util.h"
10 #include "base/strings/string_util.h"
11 #include "base/strings/stringprintf.h"
12 #include "chrome/browser/chromeos/arc/fileapi/arc_documents_provider_util.h"
13 #include "net/base/mime_util.h"
14
15 namespace arc {
16
17 namespace {
18
19 // Computes a file name for a document.
20 base::FilePath::StringType GetFileNameForDocument(
21 const mojom::DocumentPtr& document) {
22 base::FilePath::StringType filename = document->display_name;
23
24 // Replace path separators appearing in the file name.
25 // Chrome OS is POSIX and kSeparators is "/".
26 base::ReplaceChars(filename, base::FilePath::kSeparators, "_", &filename);
27
28 // Do not allow "." and "..", though this is very unlikely to happen.
29 if (filename == base::FilePath::kCurrentDirectory) {
30 filename = "dot";
hashimoto 2016/12/19 06:40:48 "dot" looks unfriendly for users who don't speak E
Shuhei Takahashi 2016/12/19 10:01:56 Thanks for the pointer, I'll follow it.
31 } else if (filename == base::FilePath::kParentDirectory) {
32 filename = "dotdot";
33 }
34
35 // Since Chrome detects MIME type from file name extensions, we need to change
36 // the file name extension of the document if it does not match with its MIME
37 // type.
38 // For example, Audio Media Provider presents a music file with its title as
39 // the file name.
40 base::FilePath::StringType extension =
41 base::ToLowerASCII(base::FilePath(filename).Extension());
42 if (!extension.empty())
43 extension = extension.substr(1); // Strip the leading dot.
44 std::vector<base::FilePath::StringType> possible_extensions;
45 net::GetExtensionsForMimeType(document->mime_type, &possible_extensions);
46 if (!possible_extensions.empty() &&
47 std::find(possible_extensions.begin(), possible_extensions.end(),
48 extension) == possible_extensions.end()) {
49 std::string new_extension;
50 if (!net::GetPreferredExtensionForMimeType(document->mime_type,
51 &new_extension)) {
52 new_extension = possible_extensions[0];
53 }
54 filename = base::FilePath(filename).AddExtension(new_extension).value();
55 }
56
57 return filename;
58 }
59
60 ArcDocumentsProviderDocument* CreateDocument(const mojom::Document& document) {
61 return new ArcDocumentsProviderDocument(
62 document.document_id, document.mime_type == kAndroidDirectoryMimeType);
63 }
64
65 } // namespace
66
67 ArcDocumentsProviderDocument::ArcDocumentsProviderDocument(
68 const std::string& document_id,
69 bool is_directory)
70 : document_id_(document_id),
71 is_directory_(is_directory),
72 children_(is_directory ? new ChildMap() : nullptr) {
73 // Constructor is called on the UI thread as opposed to other methods.
74 thread_checker_.DetachFromThread();
75 }
76
77 ArcDocumentsProviderDocument::~ArcDocumentsProviderDocument() {
78 DCHECK(thread_checker_.CalledOnValidThread());
79 }
80
81 ArcDocumentsProviderDocument* ArcDocumentsProviderDocument::Lookup(
82 const base::FilePath& path) {
83 DCHECK(thread_checker_.CalledOnValidThread());
84
85 if (path.empty())
86 return this;
87
88 ArcDocumentsProviderDocument* current = this;
89 std::vector<base::FilePath::StringType> components;
90 path.GetComponents(&components);
91
92 for (const base::FilePath::StringType& component : components) {
93 if (!current->is_directory())
94 return nullptr;
95
96 auto iter = current->children_->find(component);
97 if (iter == current->children_->end())
98 return nullptr;
99
100 current = iter->second.get();
101 }
102 return current;
103 }
104
105 void ArcDocumentsProviderDocument::UpdateWithChildDocuments(
106 const std::vector<mojom::DocumentPtr>& children) {
107 DCHECK(thread_checker_.CalledOnValidThread());
108 DCHECK(is_directory_);
109
110 ChildMap& old_map = *children_;
111 ChildMap new_map;
112
113 std::set<mojom::Document*> processed;
114
115 // If a document is in |old_map|, keep the mapping for them.
116 {
117 std::map<std::string, base::FilePath::StringType> reverse_old_map;
118 for (const auto& pair : old_map) {
119 reverse_old_map[pair.second->document_id()] = pair.first;
120 }
121 for (const mojom::DocumentPtr& child : children) {
122 auto iter = reverse_old_map.find(child->document_id);
123 if (iter == reverse_old_map.end())
124 continue;
125 new_map[iter->second].reset(CreateDocument(*child));
126 processed.insert(&*child);
127 }
128 }
129
130 // Process new documents without name conflicts.
131 {
132 std::map<base::FilePath::StringType, int> name_counters;
133 for (const mojom::DocumentPtr& child : children) {
134 if (processed.count(&*child) > 0)
135 continue;
136 name_counters[GetFileNameForDocument(child)] += 1;
137 }
138 for (const mojom::DocumentPtr& child : children) {
139 if (processed.count(&*child) > 0)
140 continue;
141 base::FilePath::StringType filename = GetFileNameForDocument(child);
142 DCHECK_GE(name_counters[filename], 1);
143 if (name_counters[filename] == 1 && new_map.count(filename) == 0) {
144 new_map[filename].reset(CreateDocument(*child));
145 processed.insert(&*child);
146 }
147 }
148 }
149
150 // Finally, deal with conflicts.
151 {
152 std::map<std::string, int> suffix_counters;
153 for (const mojom::DocumentPtr& child : children) {
154 if (processed.count(&*child) > 0)
155 continue;
156
157 base::FilePath::StringType filename = GetFileNameForDocument(child);
158
159 if (new_map.count(filename) > 0) {
160 // Resolve a conflict by adding a suffix.
161 int& suffix_counter = suffix_counters[filename];
162 while (true) {
163 ++suffix_counter;
164 std::string suffix = base::StringPrintf(" %d", suffix_counter);
165 base::FilePath::StringType new_filename =
166 base::FilePath(filename)
167 .InsertBeforeExtensionASCII(suffix)
168 .value();
169 if (new_map.count(new_filename) == 0) {
170 filename = new_filename;
171 break;
172 }
173 }
174 }
175
176 new_map[filename].reset(CreateDocument(*child));
177 processed.insert(&*child);
178 }
179 }
180
181 DCHECK_EQ(processed.size(), children.size());
182
183 old_map.swap(new_map);
184 }
185
186 } // namespace arc
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698