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

Unified 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 side-by-side diff with in-line comments
Download patch
Index: chrome/browser/chromeos/arc/fileapi/arc_documents_provider_document.cc
diff --git a/chrome/browser/chromeos/arc/fileapi/arc_documents_provider_document.cc b/chrome/browser/chromeos/arc/fileapi/arc_documents_provider_document.cc
new file mode 100644
index 0000000000000000000000000000000000000000..3b3ec8833224688846e239fec05c9627a6fac421
--- /dev/null
+++ b/chrome/browser/chromeos/arc/fileapi/arc_documents_provider_document.cc
@@ -0,0 +1,186 @@
+// Copyright 2016 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 "chrome/browser/chromeos/arc/fileapi/arc_documents_provider_document.h"
+
+#include <set>
+
+#include "base/memory/ptr_util.h"
+#include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
+#include "chrome/browser/chromeos/arc/fileapi/arc_documents_provider_util.h"
+#include "net/base/mime_util.h"
+
+namespace arc {
+
+namespace {
+
+// Computes a file name for a document.
+base::FilePath::StringType GetFileNameForDocument(
+ const mojom::DocumentPtr& document) {
+ base::FilePath::StringType filename = document->display_name;
+
+ // Replace path separators appearing in the file name.
+ // Chrome OS is POSIX and kSeparators is "/".
+ base::ReplaceChars(filename, base::FilePath::kSeparators, "_", &filename);
+
+ // Do not allow "." and "..", though this is very unlikely to happen.
+ if (filename == base::FilePath::kCurrentDirectory) {
+ 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.
+ } else if (filename == base::FilePath::kParentDirectory) {
+ filename = "dotdot";
+ }
+
+ // Since Chrome detects MIME type from file name extensions, we need to change
+ // the file name extension of the document if it does not match with its MIME
+ // type.
+ // For example, Audio Media Provider presents a music file with its title as
+ // the file name.
+ base::FilePath::StringType extension =
+ base::ToLowerASCII(base::FilePath(filename).Extension());
+ if (!extension.empty())
+ extension = extension.substr(1); // Strip the leading dot.
+ std::vector<base::FilePath::StringType> possible_extensions;
+ net::GetExtensionsForMimeType(document->mime_type, &possible_extensions);
+ if (!possible_extensions.empty() &&
+ std::find(possible_extensions.begin(), possible_extensions.end(),
+ extension) == possible_extensions.end()) {
+ std::string new_extension;
+ if (!net::GetPreferredExtensionForMimeType(document->mime_type,
+ &new_extension)) {
+ new_extension = possible_extensions[0];
+ }
+ filename = base::FilePath(filename).AddExtension(new_extension).value();
+ }
+
+ return filename;
+}
+
+ArcDocumentsProviderDocument* CreateDocument(const mojom::Document& document) {
+ return new ArcDocumentsProviderDocument(
+ document.document_id, document.mime_type == kAndroidDirectoryMimeType);
+}
+
+} // namespace
+
+ArcDocumentsProviderDocument::ArcDocumentsProviderDocument(
+ const std::string& document_id,
+ bool is_directory)
+ : document_id_(document_id),
+ is_directory_(is_directory),
+ children_(is_directory ? new ChildMap() : nullptr) {
+ // Constructor is called on the UI thread as opposed to other methods.
+ thread_checker_.DetachFromThread();
+}
+
+ArcDocumentsProviderDocument::~ArcDocumentsProviderDocument() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+}
+
+ArcDocumentsProviderDocument* ArcDocumentsProviderDocument::Lookup(
+ const base::FilePath& path) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+
+ if (path.empty())
+ return this;
+
+ ArcDocumentsProviderDocument* current = this;
+ std::vector<base::FilePath::StringType> components;
+ path.GetComponents(&components);
+
+ for (const base::FilePath::StringType& component : components) {
+ if (!current->is_directory())
+ return nullptr;
+
+ auto iter = current->children_->find(component);
+ if (iter == current->children_->end())
+ return nullptr;
+
+ current = iter->second.get();
+ }
+ return current;
+}
+
+void ArcDocumentsProviderDocument::UpdateWithChildDocuments(
+ const std::vector<mojom::DocumentPtr>& children) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK(is_directory_);
+
+ ChildMap& old_map = *children_;
+ ChildMap new_map;
+
+ std::set<mojom::Document*> processed;
+
+ // If a document is in |old_map|, keep the mapping for them.
+ {
+ std::map<std::string, base::FilePath::StringType> reverse_old_map;
+ for (const auto& pair : old_map) {
+ reverse_old_map[pair.second->document_id()] = pair.first;
+ }
+ for (const mojom::DocumentPtr& child : children) {
+ auto iter = reverse_old_map.find(child->document_id);
+ if (iter == reverse_old_map.end())
+ continue;
+ new_map[iter->second].reset(CreateDocument(*child));
+ processed.insert(&*child);
+ }
+ }
+
+ // Process new documents without name conflicts.
+ {
+ std::map<base::FilePath::StringType, int> name_counters;
+ for (const mojom::DocumentPtr& child : children) {
+ if (processed.count(&*child) > 0)
+ continue;
+ name_counters[GetFileNameForDocument(child)] += 1;
+ }
+ for (const mojom::DocumentPtr& child : children) {
+ if (processed.count(&*child) > 0)
+ continue;
+ base::FilePath::StringType filename = GetFileNameForDocument(child);
+ DCHECK_GE(name_counters[filename], 1);
+ if (name_counters[filename] == 1 && new_map.count(filename) == 0) {
+ new_map[filename].reset(CreateDocument(*child));
+ processed.insert(&*child);
+ }
+ }
+ }
+
+ // Finally, deal with conflicts.
+ {
+ std::map<std::string, int> suffix_counters;
+ for (const mojom::DocumentPtr& child : children) {
+ if (processed.count(&*child) > 0)
+ continue;
+
+ base::FilePath::StringType filename = GetFileNameForDocument(child);
+
+ if (new_map.count(filename) > 0) {
+ // Resolve a conflict by adding a suffix.
+ int& suffix_counter = suffix_counters[filename];
+ while (true) {
+ ++suffix_counter;
+ std::string suffix = base::StringPrintf(" %d", suffix_counter);
+ base::FilePath::StringType new_filename =
+ base::FilePath(filename)
+ .InsertBeforeExtensionASCII(suffix)
+ .value();
+ if (new_map.count(new_filename) == 0) {
+ filename = new_filename;
+ break;
+ }
+ }
+ }
+
+ new_map[filename].reset(CreateDocument(*child));
+ processed.insert(&*child);
+ }
+ }
+
+ DCHECK_EQ(processed.size(), children.size());
+
+ old_map.swap(new_map);
+}
+
+} // namespace arc

Powered by Google App Engine
This is Rietveld 408576698