Roll src/third_party/WebKit 9f7fb92:f103b33 (svn 202621:202622)
[chromium-blink-merge.git] / components / drive / drive_api_util.cc
blobdef16bb1a258e43d4247cd3df5f8dd6f57e06414
1 // Copyright (c) 2012 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.
5 #include "components/drive/drive_api_util.h"
7 #include <string>
9 #include "base/files/file.h"
10 #include "base/logging.h"
11 #include "base/md5.h"
12 #include "base/strings/string16.h"
13 #include "base/strings/string_util.h"
14 #include "base/strings/stringprintf.h"
15 #include "base/strings/utf_string_conversions.h"
16 #include "base/synchronization/cancellation_flag.h"
17 #include "base/values.h"
18 #include "google_apis/drive/drive_api_parser.h"
19 #include "net/base/escape.h"
20 #include "net/base/net_errors.h"
21 #include "third_party/re2/re2/re2.h"
22 #include "url/gurl.h"
24 namespace drive {
25 namespace util {
26 namespace {
28 struct HostedDocumentKind {
29 const char* mime_type;
30 const char* extension;
33 const HostedDocumentKind kHostedDocumentKinds[] = {
34 {kGoogleDocumentMimeType, ".gdoc"},
35 {kGoogleSpreadsheetMimeType, ".gsheet"},
36 {kGooglePresentationMimeType, ".gslides"},
37 {kGoogleDrawingMimeType, ".gdraw"},
38 {kGoogleTableMimeType, ".gtable"},
39 {kGoogleFormMimeType, ".gform"},
40 {kGoogleMapMimeType, ".gmaps"},
43 const char kUnknownHostedDocumentExtension[] = ".glink";
45 const int kMd5DigestBufferSize = 512 * 1024; // 512 kB.
47 } // namespace
49 std::string EscapeQueryStringValue(const std::string& str) {
50 std::string result;
51 result.reserve(str.size());
52 for (size_t i = 0; i < str.size(); ++i) {
53 if (str[i] == '\\' || str[i] == '\'') {
54 result.push_back('\\');
56 result.push_back(str[i]);
58 return result;
61 std::string TranslateQuery(const std::string& original_query) {
62 // In order to handle non-ascii white spaces correctly, convert to UTF16.
63 base::string16 query = base::UTF8ToUTF16(original_query);
64 const base::string16 kDelimiter(
65 base::kWhitespaceUTF16 + base::ASCIIToUTF16("\""));
67 std::string result;
68 for (size_t index = query.find_first_not_of(base::kWhitespaceUTF16);
69 index != base::string16::npos;
70 index = query.find_first_not_of(base::kWhitespaceUTF16, index)) {
71 bool is_exclusion = (query[index] == '-');
72 if (is_exclusion)
73 ++index;
74 if (index == query.length()) {
75 // Here, the token is '-' and it should be ignored.
76 continue;
79 size_t begin_token = index;
80 base::string16 token;
81 if (query[begin_token] == '"') {
82 // Quoted query.
83 ++begin_token;
84 size_t end_token = query.find('"', begin_token);
85 if (end_token == base::string16::npos) {
86 // This is kind of syntax error, since quoted string isn't finished.
87 // However, the query is built by user manually, so here we treat
88 // whole remaining string as a token as a fallback, by appending
89 // a missing double-quote character.
90 end_token = query.length();
91 query.push_back('"');
94 token = query.substr(begin_token, end_token - begin_token);
95 index = end_token + 1; // Consume last '"', too.
96 } else {
97 size_t end_token = query.find_first_of(kDelimiter, begin_token);
98 if (end_token == base::string16::npos) {
99 end_token = query.length();
102 token = query.substr(begin_token, end_token - begin_token);
103 index = end_token;
106 if (token.empty()) {
107 // Just ignore an empty token.
108 continue;
111 if (!result.empty()) {
112 // If there are two or more tokens, need to connect with "and".
113 result.append(" and ");
116 // The meaning of "fullText" should include title, description and content.
117 base::StringAppendF(
118 &result,
119 "%sfullText contains \'%s\'",
120 is_exclusion ? "not " : "",
121 EscapeQueryStringValue(base::UTF16ToUTF8(token)).c_str());
124 return result;
127 std::string CanonicalizeResourceId(const std::string& resource_id) {
128 // If resource ID is in the old WAPI format starting with a prefix like
129 // "document:", strip it and return the remaining part.
130 std::string stripped_resource_id;
131 if (RE2::FullMatch(resource_id, "^[a-z-]+(?::|%3A)([\\w-]+)$",
132 &stripped_resource_id))
133 return stripped_resource_id;
134 return resource_id;
137 std::string GetMd5Digest(const base::FilePath& file_path,
138 const base::CancellationFlag* cancellation_flag) {
139 base::File file(file_path, base::File::FLAG_OPEN | base::File::FLAG_READ);
140 if (!file.IsValid())
141 return std::string();
143 base::MD5Context context;
144 base::MD5Init(&context);
146 int64 offset = 0;
147 scoped_ptr<char[]> buffer(new char[kMd5DigestBufferSize]);
148 while (true) {
149 if (cancellation_flag && cancellation_flag->IsSet()) { // Cancelled.
150 return std::string();
152 int result = file.Read(offset, buffer.get(), kMd5DigestBufferSize);
153 if (result < 0) {
154 // Found an error.
155 return std::string();
158 if (result == 0) {
159 // End of file.
160 break;
163 offset += result;
164 base::MD5Update(&context, base::StringPiece(buffer.get(), result));
167 base::MD5Digest digest;
168 base::MD5Final(&digest, &context);
169 return base::MD5DigestToBase16(digest);
172 std::string GetHostedDocumentExtension(const std::string& mime_type) {
173 for (size_t i = 0; i < arraysize(kHostedDocumentKinds); ++i) {
174 if (mime_type == kHostedDocumentKinds[i].mime_type)
175 return kHostedDocumentKinds[i].extension;
177 return kUnknownHostedDocumentExtension;
180 bool IsKnownHostedDocumentMimeType(const std::string& mime_type) {
181 for (size_t i = 0; i < arraysize(kHostedDocumentKinds); ++i) {
182 if (mime_type == kHostedDocumentKinds[i].mime_type)
183 return true;
185 return false;
188 bool HasHostedDocumentExtension(const base::FilePath& path) {
189 const std::string extension = base::FilePath(path.Extension()).AsUTF8Unsafe();
190 for (size_t i = 0; i < arraysize(kHostedDocumentKinds); ++i) {
191 if (extension == kHostedDocumentKinds[i].extension)
192 return true;
194 return extension == kUnknownHostedDocumentExtension;
197 } // namespace util
198 } // namespace drive