This source file includes following definitions.
- GetMimeTypeFromEntryKind
- CopyScopedVectorString
- ConvertAppIconToDriveAppIcon
- ConvertInstalledAppToAppResource
- Identity
- EscapeQueryStringValue
- TranslateQuery
- ExtractResourceIdFromUrl
- CanonicalizeResourceId
- GetIdentityResourceIdCanonicalizer
- ParseShareUrlAndRun
- ConvertAccountMetadataToAboutResource
- ConvertAccountMetadataToAppList
- ConvertResourceEntryToFileResource
- GetKind
- ConvertFileResourceToResourceEntry
- ConvertChangeResourceToResourceEntry
- ConvertFileListToResourceList
- ConvertChangeListToResourceList
- GetMd5Digest
#include "chrome/browser/drive/drive_api_util.h"
#include <string>
#include "base/files/file.h"
#include "base/logging.h"
#include "base/md5.h"
#include "base/strings/string16.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/values.h"
#include "content/public/browser/browser_thread.h"
#include "google_apis/drive/drive_api_parser.h"
#include "google_apis/drive/gdata_wapi_parser.h"
#include "net/base/escape.h"
#include "third_party/re2/re2/re2.h"
#include "url/gurl.h"
namespace drive {
namespace util {
namespace {
const char kGoogleDocumentMimeType[] = "application/vnd.google-apps.document";
const char kGoogleDrawingMimeType[] = "application/vnd.google-apps.drawing";
const char kGooglePresentationMimeType[] =
"application/vnd.google-apps.presentation";
const char kGoogleSpreadsheetMimeType[] =
"application/vnd.google-apps.spreadsheet";
const char kGoogleTableMimeType[] = "application/vnd.google-apps.table";
const char kGoogleFormMimeType[] = "application/vnd.google-apps.form";
const char kDriveFolderMimeType[] = "application/vnd.google-apps.folder";
std::string GetMimeTypeFromEntryKind(google_apis::DriveEntryKind kind) {
switch (kind) {
case google_apis::ENTRY_KIND_DOCUMENT:
return kGoogleDocumentMimeType;
case google_apis::ENTRY_KIND_SPREADSHEET:
return kGoogleSpreadsheetMimeType;
case google_apis::ENTRY_KIND_PRESENTATION:
return kGooglePresentationMimeType;
case google_apis::ENTRY_KIND_DRAWING:
return kGoogleDrawingMimeType;
case google_apis::ENTRY_KIND_TABLE:
return kGoogleTableMimeType;
case google_apis::ENTRY_KIND_FORM:
return kGoogleFormMimeType;
default:
return std::string();
}
}
ScopedVector<std::string> CopyScopedVectorString(
const ScopedVector<std::string>& source) {
ScopedVector<std::string> result;
result.reserve(source.size());
for (size_t i = 0; i < source.size(); ++i)
result.push_back(new std::string(*source[i]));
return result.Pass();
}
scoped_ptr<google_apis::DriveAppIcon>
ConvertAppIconToDriveAppIcon(const google_apis::AppIcon& app_icon) {
scoped_ptr<google_apis::DriveAppIcon> resource(
new google_apis::DriveAppIcon);
switch (app_icon.category()) {
case google_apis::AppIcon::ICON_UNKNOWN:
resource->set_category(google_apis::DriveAppIcon::UNKNOWN);
break;
case google_apis::AppIcon::ICON_DOCUMENT:
resource->set_category(google_apis::DriveAppIcon::DOCUMENT);
break;
case google_apis::AppIcon::ICON_APPLICATION:
resource->set_category(google_apis::DriveAppIcon::APPLICATION);
break;
case google_apis::AppIcon::ICON_SHARED_DOCUMENT:
resource->set_category(google_apis::DriveAppIcon::SHARED_DOCUMENT);
break;
default:
NOTREACHED();
}
resource->set_icon_side_length(app_icon.icon_side_length());
resource->set_icon_url(app_icon.GetIconURL());
return resource.Pass();
}
scoped_ptr<google_apis::AppResource>
ConvertInstalledAppToAppResource(
const google_apis::InstalledApp& installed_app) {
scoped_ptr<google_apis::AppResource> resource(new google_apis::AppResource);
resource->set_application_id(installed_app.app_id());
resource->set_name(installed_app.app_name());
resource->set_object_type(installed_app.object_type());
resource->set_supports_create(installed_app.supports_create());
{
ScopedVector<std::string> primary_mimetypes(
CopyScopedVectorString(installed_app.primary_mimetypes()));
resource->set_primary_mimetypes(primary_mimetypes.Pass());
}
{
ScopedVector<std::string> secondary_mimetypes(
CopyScopedVectorString(installed_app.secondary_mimetypes()));
resource->set_secondary_mimetypes(secondary_mimetypes.Pass());
}
{
ScopedVector<std::string> primary_file_extensions(
CopyScopedVectorString(installed_app.primary_extensions()));
resource->set_primary_file_extensions(primary_file_extensions.Pass());
}
{
ScopedVector<std::string> secondary_file_extensions(
CopyScopedVectorString(installed_app.secondary_extensions()));
resource->set_secondary_file_extensions(secondary_file_extensions.Pass());
}
{
const ScopedVector<google_apis::AppIcon>& app_icons =
installed_app.app_icons();
ScopedVector<google_apis::DriveAppIcon> icons;
icons.reserve(app_icons.size());
for (size_t i = 0; i < app_icons.size(); ++i) {
icons.push_back(ConvertAppIconToDriveAppIcon(*app_icons[i]).release());
}
resource->set_icons(icons.Pass());
}
return resource.Pass();
}
std::string Identity(const std::string& resource_id) { return resource_id; }
}
std::string EscapeQueryStringValue(const std::string& str) {
std::string result;
result.reserve(str.size());
for (size_t i = 0; i < str.size(); ++i) {
if (str[i] == '\\' || str[i] == '\'') {
result.push_back('\\');
}
result.push_back(str[i]);
}
return result;
}
std::string TranslateQuery(const std::string& original_query) {
base::string16 query = base::UTF8ToUTF16(original_query);
const base::string16 kDelimiter(
base::kWhitespaceUTF16 +
base::string16(1, static_cast<base::char16>('"')));
std::string result;
for (size_t index = query.find_first_not_of(base::kWhitespaceUTF16);
index != base::string16::npos;
index = query.find_first_not_of(base::kWhitespaceUTF16, index)) {
bool is_exclusion = (query[index] == '-');
if (is_exclusion)
++index;
if (index == query.length()) {
continue;
}
size_t begin_token = index;
base::string16 token;
if (query[begin_token] == '"') {
++begin_token;
size_t end_token = query.find('"', begin_token);
if (end_token == base::string16::npos) {
end_token = query.length();
query.push_back('"');
}
token = query.substr(begin_token, end_token - begin_token);
index = end_token + 1;
} else {
size_t end_token = query.find_first_of(kDelimiter, begin_token);
if (end_token == base::string16::npos) {
end_token = query.length();
}
token = query.substr(begin_token, end_token - begin_token);
index = end_token;
}
if (token.empty()) {
continue;
}
if (!result.empty()) {
result.append(" and ");
}
base::StringAppendF(
&result,
"%sfullText contains \'%s\'",
is_exclusion ? "not " : "",
EscapeQueryStringValue(base::UTF16ToUTF8(token)).c_str());
}
return result;
}
std::string ExtractResourceIdFromUrl(const GURL& url) {
return net::UnescapeURLComponent(url.ExtractFileName(),
net::UnescapeRule::URL_SPECIAL_CHARS);
}
std::string CanonicalizeResourceId(const std::string& resource_id) {
std::string stripped_resource_id;
if (RE2::FullMatch(resource_id, "^[a-z-]+(?::|%3A)([\\w-]+)$",
&stripped_resource_id))
return stripped_resource_id;
return resource_id;
}
ResourceIdCanonicalizer GetIdentityResourceIdCanonicalizer() {
return base::Bind(&Identity);
}
const char kDocsListScope[] = "https://docs.google.com/feeds/";
const char kDriveAppsScope[] = "https://www.googleapis.com/auth/drive.apps";
void ParseShareUrlAndRun(const google_apis::GetShareUrlCallback& callback,
google_apis::GDataErrorCode error,
scoped_ptr<base::Value> value) {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
if (!value) {
callback.Run(error, GURL());
return;
}
scoped_ptr<google_apis::ResourceEntry> entry =
google_apis::ResourceEntry::ExtractAndParse(*value);
if (!entry) {
callback.Run(google_apis::GDATA_PARSE_ERROR, GURL());
return;
}
const google_apis::Link* share_link =
entry->GetLinkByType(google_apis::Link::LINK_SHARE);
callback.Run(error, share_link ? share_link->href() : GURL());
}
scoped_ptr<google_apis::AboutResource>
ConvertAccountMetadataToAboutResource(
const google_apis::AccountMetadata& account_metadata,
const std::string& root_resource_id) {
scoped_ptr<google_apis::AboutResource> resource(
new google_apis::AboutResource);
resource->set_largest_change_id(account_metadata.largest_changestamp());
resource->set_quota_bytes_total(account_metadata.quota_bytes_total());
resource->set_quota_bytes_used(account_metadata.quota_bytes_used());
resource->set_root_folder_id(root_resource_id);
return resource.Pass();
}
scoped_ptr<google_apis::AppList>
ConvertAccountMetadataToAppList(
const google_apis::AccountMetadata& account_metadata) {
scoped_ptr<google_apis::AppList> resource(new google_apis::AppList);
const ScopedVector<google_apis::InstalledApp>& installed_apps =
account_metadata.installed_apps();
ScopedVector<google_apis::AppResource> app_resources;
app_resources.reserve(installed_apps.size());
for (size_t i = 0; i < installed_apps.size(); ++i) {
app_resources.push_back(
ConvertInstalledAppToAppResource(*installed_apps[i]).release());
}
resource->set_items(app_resources.Pass());
return resource.Pass();
}
scoped_ptr<google_apis::FileResource> ConvertResourceEntryToFileResource(
const google_apis::ResourceEntry& entry) {
scoped_ptr<google_apis::FileResource> file(new google_apis::FileResource);
file->set_file_id(entry.resource_id());
file->set_title(entry.title());
file->set_created_date(entry.published_time());
if (std::find(entry.labels().begin(), entry.labels().end(),
"shared-with-me") != entry.labels().end()) {
file->set_shared_with_me_date(base::Time::Now());
}
file->set_shared(std::find(entry.labels().begin(), entry.labels().end(),
"shared") != entry.labels().end());
if (entry.is_folder()) {
file->set_mime_type(kDriveFolderMimeType);
} else {
std::string mime_type = GetMimeTypeFromEntryKind(entry.kind());
if (mime_type.empty())
mime_type = entry.content_mime_type();
file->set_mime_type(mime_type);
}
file->set_md5_checksum(entry.file_md5());
file->set_file_size(entry.file_size());
file->mutable_labels()->set_trashed(entry.deleted());
file->set_etag(entry.etag());
google_apis::ImageMediaMetadata* image_media_metadata =
file->mutable_image_media_metadata();
image_media_metadata->set_width(entry.image_width());
image_media_metadata->set_height(entry.image_height());
image_media_metadata->set_rotation(entry.image_rotation());
std::vector<google_apis::ParentReference>* parents = file->mutable_parents();
for (size_t i = 0; i < entry.links().size(); ++i) {
using google_apis::Link;
const Link& link = *entry.links()[i];
switch (link.type()) {
case Link::LINK_PARENT: {
google_apis::ParentReference parent;
parent.set_parent_link(link.href());
std::string file_id =
drive::util::ExtractResourceIdFromUrl(link.href());
parent.set_file_id(file_id);
parent.set_is_root(file_id == kWapiRootDirectoryResourceId);
parents->push_back(parent);
break;
}
case Link::LINK_ALTERNATE:
file->set_alternate_link(link.href());
break;
default:
break;
}
}
file->set_modified_date(entry.updated_time());
file->set_last_viewed_by_me_date(entry.last_viewed_time());
return file.Pass();
}
google_apis::DriveEntryKind GetKind(
const google_apis::FileResource& file_resource) {
if (file_resource.IsDirectory())
return google_apis::ENTRY_KIND_FOLDER;
const std::string& mime_type = file_resource.mime_type();
if (mime_type == kGoogleDocumentMimeType)
return google_apis::ENTRY_KIND_DOCUMENT;
if (mime_type == kGoogleSpreadsheetMimeType)
return google_apis::ENTRY_KIND_SPREADSHEET;
if (mime_type == kGooglePresentationMimeType)
return google_apis::ENTRY_KIND_PRESENTATION;
if (mime_type == kGoogleDrawingMimeType)
return google_apis::ENTRY_KIND_DRAWING;
if (mime_type == kGoogleTableMimeType)
return google_apis::ENTRY_KIND_TABLE;
if (mime_type == kGoogleFormMimeType)
return google_apis::ENTRY_KIND_FORM;
if (mime_type == "application/pdf")
return google_apis::ENTRY_KIND_PDF;
return google_apis::ENTRY_KIND_FILE;
}
scoped_ptr<google_apis::ResourceEntry>
ConvertFileResourceToResourceEntry(
const google_apis::FileResource& file_resource) {
scoped_ptr<google_apis::ResourceEntry> entry(new google_apis::ResourceEntry);
entry->set_resource_id(file_resource.file_id());
entry->set_id(file_resource.file_id());
entry->set_kind(GetKind(file_resource));
entry->set_title(file_resource.title());
entry->set_published_time(file_resource.created_date());
std::vector<std::string> labels;
if (!file_resource.shared_with_me_date().is_null())
labels.push_back("shared-with-me");
if (file_resource.shared())
labels.push_back("shared");
entry->set_labels(labels);
{
google_apis::Content content;
content.set_mime_type(file_resource.mime_type());
entry->set_content(content);
}
entry->set_filename(file_resource.title());
entry->set_suggested_filename(file_resource.title());
entry->set_file_md5(file_resource.md5_checksum());
entry->set_file_size(file_resource.file_size());
entry->set_deleted(file_resource.labels().is_trashed());
entry->set_image_width(file_resource.image_media_metadata().width());
entry->set_image_height(file_resource.image_media_metadata().height());
entry->set_image_rotation(file_resource.image_media_metadata().rotation());
entry->set_etag(file_resource.etag());
ScopedVector<google_apis::Link> links;
for (size_t i = 0; i < file_resource.parents().size(); ++i) {
google_apis::Link* link = new google_apis::Link;
link->set_type(google_apis::Link::LINK_PARENT);
link->set_href(file_resource.parents()[i].parent_link());
links.push_back(link);
}
if (!file_resource.alternate_link().is_empty()) {
google_apis::Link* link = new google_apis::Link;
link->set_type(google_apis::Link::LINK_ALTERNATE);
link->set_href(file_resource.alternate_link());
links.push_back(link);
}
entry->set_links(links.Pass());
entry->set_updated_time(file_resource.modified_date());
entry->set_last_viewed_time(file_resource.last_viewed_by_me_date());
entry->FillRemainingFields();
return entry.Pass();
}
scoped_ptr<google_apis::ResourceEntry>
ConvertChangeResourceToResourceEntry(
const google_apis::ChangeResource& change_resource) {
scoped_ptr<google_apis::ResourceEntry> entry;
if (change_resource.file())
entry = ConvertFileResourceToResourceEntry(*change_resource.file()).Pass();
else
entry.reset(new google_apis::ResourceEntry);
entry->set_resource_id(change_resource.file_id());
entry->set_removed(change_resource.is_deleted());
entry->set_changestamp(change_resource.change_id());
entry->set_modification_date(change_resource.modification_date());
return entry.Pass();
}
scoped_ptr<google_apis::ResourceList>
ConvertFileListToResourceList(const google_apis::FileList& file_list) {
scoped_ptr<google_apis::ResourceList> feed(new google_apis::ResourceList);
const ScopedVector<google_apis::FileResource>& items = file_list.items();
ScopedVector<google_apis::ResourceEntry> entries;
for (size_t i = 0; i < items.size(); ++i)
entries.push_back(ConvertFileResourceToResourceEntry(*items[i]).release());
feed->set_entries(entries.Pass());
ScopedVector<google_apis::Link> links;
if (!file_list.next_link().is_empty()) {
google_apis::Link* link = new google_apis::Link;
link->set_type(google_apis::Link::LINK_NEXT);
link->set_href(file_list.next_link());
links.push_back(link);
}
feed->set_links(links.Pass());
return feed.Pass();
}
scoped_ptr<google_apis::ResourceList>
ConvertChangeListToResourceList(const google_apis::ChangeList& change_list) {
scoped_ptr<google_apis::ResourceList> feed(new google_apis::ResourceList);
const ScopedVector<google_apis::ChangeResource>& items = change_list.items();
ScopedVector<google_apis::ResourceEntry> entries;
for (size_t i = 0; i < items.size(); ++i) {
entries.push_back(
ConvertChangeResourceToResourceEntry(*items[i]).release());
}
feed->set_entries(entries.Pass());
feed->set_largest_changestamp(change_list.largest_change_id());
ScopedVector<google_apis::Link> links;
if (!change_list.next_link().is_empty()) {
google_apis::Link* link = new google_apis::Link;
link->set_type(google_apis::Link::LINK_NEXT);
link->set_href(change_list.next_link());
links.push_back(link);
}
feed->set_links(links.Pass());
return feed.Pass();
}
std::string GetMd5Digest(const base::FilePath& file_path) {
const int kBufferSize = 512 * 1024;
base::File file(file_path, base::File::FLAG_OPEN | base::File::FLAG_READ);
if (!file.IsValid())
return std::string();
base::MD5Context context;
base::MD5Init(&context);
int64 offset = 0;
scoped_ptr<char[]> buffer(new char[kBufferSize]);
while (true) {
int result = file.Read(offset, buffer.get(), kBufferSize);
if (result < 0) {
return std::string();
}
if (result == 0) {
break;
}
offset += result;
base::MD5Update(&context, base::StringPiece(buffer.get(), result));
}
base::MD5Digest digest;
base::MD5Final(&digest, &context);
return MD5DigestToBase16(digest);
}
const char kWapiRootDirectoryResourceId[] = "folder:root";
}
}