cc: Convert LTHCommon tests to LayerImpl
[chromium-blink-merge.git] / components / drive / drive_api_util.cc
blob57c391913e4d046f6ae2fbf54824defeeb3b3042
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/io_buffer.h"
21 #include "net/base/net_errors.h"
22 #include "storage/browser/fileapi/file_stream_reader.h"
23 #include "third_party/re2/re2/re2.h"
24 #include "url/gurl.h"
26 namespace drive {
27 namespace util {
28 namespace {
30 struct HostedDocumentKind {
31 const char* mime_type;
32 const char* extension;
35 const HostedDocumentKind kHostedDocumentKinds[] = {
36 {kGoogleDocumentMimeType, ".gdoc"},
37 {kGoogleSpreadsheetMimeType, ".gsheet"},
38 {kGooglePresentationMimeType, ".gslides"},
39 {kGoogleDrawingMimeType, ".gdraw"},
40 {kGoogleTableMimeType, ".gtable"},
41 {kGoogleFormMimeType, ".gform"},
42 {kGoogleMapMimeType, ".gmaps"},
45 const char kUnknownHostedDocumentExtension[] = ".glink";
47 const int kMd5DigestBufferSize = 512 * 1024; // 512 kB.
49 } // namespace
51 std::string EscapeQueryStringValue(const std::string& str) {
52 std::string result;
53 result.reserve(str.size());
54 for (size_t i = 0; i < str.size(); ++i) {
55 if (str[i] == '\\' || str[i] == '\'') {
56 result.push_back('\\');
58 result.push_back(str[i]);
60 return result;
63 std::string TranslateQuery(const std::string& original_query) {
64 // In order to handle non-ascii white spaces correctly, convert to UTF16.
65 base::string16 query = base::UTF8ToUTF16(original_query);
66 const base::string16 kDelimiter(
67 base::kWhitespaceUTF16 + base::ASCIIToUTF16("\""));
69 std::string result;
70 for (size_t index = query.find_first_not_of(base::kWhitespaceUTF16);
71 index != base::string16::npos;
72 index = query.find_first_not_of(base::kWhitespaceUTF16, index)) {
73 bool is_exclusion = (query[index] == '-');
74 if (is_exclusion)
75 ++index;
76 if (index == query.length()) {
77 // Here, the token is '-' and it should be ignored.
78 continue;
81 size_t begin_token = index;
82 base::string16 token;
83 if (query[begin_token] == '"') {
84 // Quoted query.
85 ++begin_token;
86 size_t end_token = query.find('"', begin_token);
87 if (end_token == base::string16::npos) {
88 // This is kind of syntax error, since quoted string isn't finished.
89 // However, the query is built by user manually, so here we treat
90 // whole remaining string as a token as a fallback, by appending
91 // a missing double-quote character.
92 end_token = query.length();
93 query.push_back('"');
96 token = query.substr(begin_token, end_token - begin_token);
97 index = end_token + 1; // Consume last '"', too.
98 } else {
99 size_t end_token = query.find_first_of(kDelimiter, begin_token);
100 if (end_token == base::string16::npos) {
101 end_token = query.length();
104 token = query.substr(begin_token, end_token - begin_token);
105 index = end_token;
108 if (token.empty()) {
109 // Just ignore an empty token.
110 continue;
113 if (!result.empty()) {
114 // If there are two or more tokens, need to connect with "and".
115 result.append(" and ");
118 // The meaning of "fullText" should include title, description and content.
119 base::StringAppendF(
120 &result,
121 "%sfullText contains \'%s\'",
122 is_exclusion ? "not " : "",
123 EscapeQueryStringValue(base::UTF16ToUTF8(token)).c_str());
126 return result;
129 std::string CanonicalizeResourceId(const std::string& resource_id) {
130 // If resource ID is in the old WAPI format starting with a prefix like
131 // "document:", strip it and return the remaining part.
132 std::string stripped_resource_id;
133 if (RE2::FullMatch(resource_id, "^[a-z-]+(?::|%3A)([\\w-]+)$",
134 &stripped_resource_id))
135 return stripped_resource_id;
136 return resource_id;
139 std::string GetMd5Digest(const base::FilePath& file_path,
140 const base::CancellationFlag* cancellation_flag) {
141 base::File file(file_path, base::File::FLAG_OPEN | base::File::FLAG_READ);
142 if (!file.IsValid())
143 return std::string();
145 base::MD5Context context;
146 base::MD5Init(&context);
148 int64 offset = 0;
149 scoped_ptr<char[]> buffer(new char[kMd5DigestBufferSize]);
150 while (true) {
151 if (cancellation_flag && cancellation_flag->IsSet()) { // Cancelled.
152 return std::string();
154 int result = file.Read(offset, buffer.get(), kMd5DigestBufferSize);
155 if (result < 0) {
156 // Found an error.
157 return std::string();
160 if (result == 0) {
161 // End of file.
162 break;
165 offset += result;
166 base::MD5Update(&context, base::StringPiece(buffer.get(), result));
169 base::MD5Digest digest;
170 base::MD5Final(&digest, &context);
171 return base::MD5DigestToBase16(digest);
174 FileStreamMd5Digester::FileStreamMd5Digester()
175 : buffer_(new net::IOBuffer(kMd5DigestBufferSize)) {
178 FileStreamMd5Digester::~FileStreamMd5Digester() {
181 void FileStreamMd5Digester::GetMd5Digest(
182 scoped_ptr<storage::FileStreamReader> stream_reader,
183 const ResultCallback& callback) {
184 reader_ = stream_reader.Pass();
185 base::MD5Init(&md5_context_);
187 // Start the read/hash.
188 ReadNextChunk(callback);
191 void FileStreamMd5Digester::ReadNextChunk(const ResultCallback& callback) {
192 const int result =
193 reader_->Read(buffer_.get(), kMd5DigestBufferSize,
194 base::Bind(&FileStreamMd5Digester::OnChunkRead,
195 base::Unretained(this), callback));
196 if (result != net::ERR_IO_PENDING)
197 OnChunkRead(callback, result);
200 void FileStreamMd5Digester::OnChunkRead(const ResultCallback& callback,
201 int bytes_read) {
202 if (bytes_read < 0) {
203 // Error - just return empty string.
204 callback.Run("");
205 return;
206 } else if (bytes_read == 0) {
207 // EOF.
208 base::MD5Digest digest;
209 base::MD5Final(&digest, &md5_context_);
210 std::string result = base::MD5DigestToBase16(digest);
211 callback.Run(result);
212 return;
215 // Read data and digest it.
216 base::MD5Update(&md5_context_,
217 base::StringPiece(buffer_->data(), bytes_read));
219 // Kick off the next read.
220 ReadNextChunk(callback);
223 std::string GetHostedDocumentExtension(const std::string& mime_type) {
224 for (size_t i = 0; i < arraysize(kHostedDocumentKinds); ++i) {
225 if (mime_type == kHostedDocumentKinds[i].mime_type)
226 return kHostedDocumentKinds[i].extension;
228 return kUnknownHostedDocumentExtension;
231 bool IsKnownHostedDocumentMimeType(const std::string& mime_type) {
232 for (size_t i = 0; i < arraysize(kHostedDocumentKinds); ++i) {
233 if (mime_type == kHostedDocumentKinds[i].mime_type)
234 return true;
236 return false;
239 bool HasHostedDocumentExtension(const base::FilePath& path) {
240 const std::string extension = base::FilePath(path.Extension()).AsUTF8Unsafe();
241 for (size_t i = 0; i < arraysize(kHostedDocumentKinds); ++i) {
242 if (extension == kHostedDocumentKinds[i].extension)
243 return true;
245 return extension == kUnknownHostedDocumentExtension;
248 } // namespace util
249 } // namespace drive