drive_api_util.cc 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  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.
  4. #include "components/drive/drive_api_util.h"
  5. #include <string>
  6. #include "base/files/file.h"
  7. #include "base/hash/md5.h"
  8. #include "base/strings/strcat.h"
  9. #include "base/strings/string_util.h"
  10. #include "base/strings/stringprintf.h"
  11. #include "base/strings/utf_string_conversions.h"
  12. #include "base/synchronization/atomic_flag.h"
  13. #include "third_party/re2/src/re2/re2.h"
  14. namespace drive {
  15. namespace util {
  16. namespace {
  17. struct HostedDocumentKind {
  18. const char* mime_type;
  19. const char* extension;
  20. };
  21. const HostedDocumentKind kHostedDocumentKinds[] = {
  22. {kGoogleDocumentMimeType, ".gdoc"},
  23. {kGoogleSpreadsheetMimeType, ".gsheet"},
  24. {kGooglePresentationMimeType, ".gslides"},
  25. {kGoogleDrawingMimeType, ".gdraw"},
  26. {kGoogleTableMimeType, ".gtable"},
  27. {kGoogleFormMimeType, ".gform"},
  28. {kGoogleMapMimeType, ".gmaps"},
  29. {kGoogleSiteMimeType, ".gsite"},
  30. };
  31. const char kUnknownHostedDocumentExtension[] = ".glink";
  32. const int kMd5DigestBufferSize = 512 * 1024; // 512 kB.
  33. } // namespace
  34. std::string EscapeQueryStringValue(const std::string& str) {
  35. std::string result;
  36. result.reserve(str.size());
  37. for (size_t i = 0; i < str.size(); ++i) {
  38. if (str[i] == '\\' || str[i] == '\'') {
  39. result.push_back('\\');
  40. }
  41. result.push_back(str[i]);
  42. }
  43. return result;
  44. }
  45. std::string TranslateQuery(const std::string& original_query) {
  46. // In order to handle non-ascii white spaces correctly, convert to UTF16.
  47. std::u16string query = base::UTF8ToUTF16(original_query);
  48. const std::u16string kDelimiter =
  49. base::StrCat({base::kWhitespaceUTF16, u"\""});
  50. std::string result;
  51. for (size_t index = query.find_first_not_of(base::kWhitespaceUTF16);
  52. index != std::u16string::npos;
  53. index = query.find_first_not_of(base::kWhitespaceUTF16, index)) {
  54. bool is_exclusion = (query[index] == '-');
  55. if (is_exclusion)
  56. ++index;
  57. if (index == query.length()) {
  58. // Here, the token is '-' and it should be ignored.
  59. continue;
  60. }
  61. size_t begin_token = index;
  62. std::u16string token;
  63. if (query[begin_token] == '"') {
  64. // Quoted query.
  65. ++begin_token;
  66. size_t end_token = query.find('"', begin_token);
  67. if (end_token == std::u16string::npos) {
  68. // This is kind of syntax error, since quoted string isn't finished.
  69. // However, the query is built by user manually, so here we treat
  70. // whole remaining string as a token as a fallback, by appending
  71. // a missing double-quote character.
  72. end_token = query.length();
  73. query.push_back('"');
  74. }
  75. token = query.substr(begin_token, end_token - begin_token);
  76. index = end_token + 1; // Consume last '"', too.
  77. } else {
  78. size_t end_token = query.find_first_of(kDelimiter, begin_token);
  79. if (end_token == std::u16string::npos) {
  80. end_token = query.length();
  81. }
  82. token = query.substr(begin_token, end_token - begin_token);
  83. index = end_token;
  84. }
  85. if (token.empty()) {
  86. // Just ignore an empty token.
  87. continue;
  88. }
  89. if (!result.empty()) {
  90. // If there are two or more tokens, need to connect with "and".
  91. result.append(" and ");
  92. }
  93. // The meaning of "fullText" should include title, description and content.
  94. base::StringAppendF(
  95. &result,
  96. "%sfullText contains \'%s\'",
  97. is_exclusion ? "not " : "",
  98. EscapeQueryStringValue(base::UTF16ToUTF8(token)).c_str());
  99. }
  100. return result;
  101. }
  102. std::string CanonicalizeResourceId(const std::string& resource_id) {
  103. // If resource ID is in the old WAPI format starting with a prefix like
  104. // "document:", strip it and return the remaining part.
  105. std::string stripped_resource_id;
  106. if (RE2::FullMatch(resource_id, "^[a-z-]+(?::|%3A)([\\w-]+)$",
  107. &stripped_resource_id))
  108. return stripped_resource_id;
  109. return resource_id;
  110. }
  111. std::string GetMd5Digest(const base::FilePath& file_path,
  112. const base::AtomicFlag* cancellation_flag) {
  113. base::File file(file_path, base::File::FLAG_OPEN | base::File::FLAG_READ);
  114. if (!file.IsValid())
  115. return std::string();
  116. base::MD5Context context;
  117. base::MD5Init(&context);
  118. int64_t offset = 0;
  119. std::unique_ptr<char[]> buffer(new char[kMd5DigestBufferSize]);
  120. while (true) {
  121. if (cancellation_flag && cancellation_flag->IsSet()) { // Cancelled.
  122. return std::string();
  123. }
  124. int result = file.Read(offset, buffer.get(), kMd5DigestBufferSize);
  125. if (result < 0) {
  126. // Found an error.
  127. return std::string();
  128. }
  129. if (result == 0) {
  130. // End of file.
  131. break;
  132. }
  133. offset += result;
  134. base::MD5Update(&context, base::StringPiece(buffer.get(), result));
  135. }
  136. base::MD5Digest digest;
  137. base::MD5Final(&digest, &context);
  138. return base::MD5DigestToBase16(digest);
  139. }
  140. bool IsKnownHostedDocumentMimeType(const std::string& mime_type) {
  141. for (size_t i = 0; i < std::size(kHostedDocumentKinds); ++i) {
  142. if (mime_type == kHostedDocumentKinds[i].mime_type)
  143. return true;
  144. }
  145. return false;
  146. }
  147. bool HasHostedDocumentExtension(const base::FilePath& path) {
  148. const std::string extension = base::FilePath(path.Extension()).AsUTF8Unsafe();
  149. for (size_t i = 0; i < std::size(kHostedDocumentKinds); ++i) {
  150. if (extension == kHostedDocumentKinds[i].extension)
  151. return true;
  152. }
  153. return extension == kUnknownHostedDocumentExtension;
  154. }
  155. } // namespace util
  156. } // namespace drive