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"
9 #include "base/files/file.h"
10 #include "base/logging.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"
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.
49 std::string
EscapeQueryStringValue(const std::string
& str
) {
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
]);
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("\""));
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
] == '-');
74 if (index
== query
.length()) {
75 // Here, the token is '-' and it should be ignored.
79 size_t begin_token
= index
;
81 if (query
[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();
94 token
= query
.substr(begin_token
, end_token
- begin_token
);
95 index
= end_token
+ 1; // Consume last '"', too.
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
);
107 // Just ignore an empty token.
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.
119 "%sfullText contains \'%s\'",
120 is_exclusion
? "not " : "",
121 EscapeQueryStringValue(base::UTF16ToUTF8(token
)).c_str());
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
;
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
);
141 return std::string();
143 base::MD5Context context
;
144 base::MD5Init(&context
);
147 scoped_ptr
<char[]> buffer(new char[kMd5DigestBufferSize
]);
149 if (cancellation_flag
&& cancellation_flag
->IsSet()) { // Cancelled.
150 return std::string();
152 int result
= file
.Read(offset
, buffer
.get(), kMd5DigestBufferSize
);
155 return std::string();
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
)
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
)
194 return extension
== kUnknownHostedDocumentExtension
;