| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/chromeos/gdata/gdata_files.h" | 5 #include "chrome/browser/chromeos/gdata/gdata_files.h" |
| 6 | 6 |
| 7 #include <vector> | 7 #include <vector> |
| 8 | 8 |
| 9 #include "base/utf_string_conversions.h" | 9 #include "base/utf_string_conversions.h" |
| 10 #include "base/platform_file.h" | 10 #include "base/platform_file.h" |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 70 // Paste paths parts back together in reverse order from upward tree | 70 // Paste paths parts back together in reverse order from upward tree |
| 71 // traversal. | 71 // traversal. |
| 72 for (std::vector<FilePath::StringType>::reverse_iterator iter = | 72 for (std::vector<FilePath::StringType>::reverse_iterator iter = |
| 73 parts.rbegin(); | 73 parts.rbegin(); |
| 74 iter != parts.rend(); ++iter) { | 74 iter != parts.rend(); ++iter) { |
| 75 path = path.Append(*iter); | 75 path = path.Append(*iter); |
| 76 } | 76 } |
| 77 return path; | 77 return path; |
| 78 } | 78 } |
| 79 | 79 |
| 80 void GDataFileBase::SetFileNameFromTitle() { |
| 81 file_name_ = EscapeUtf8FileName(title_); |
| 82 } |
| 83 |
| 80 // static. | 84 // static. |
| 81 GDataFileBase* GDataFileBase::FromDocumentEntry(GDataDirectory* parent, | 85 GDataFileBase* GDataFileBase::FromDocumentEntry(GDataDirectory* parent, |
| 82 DocumentEntry* doc) { | 86 DocumentEntry* doc) { |
| 83 DCHECK(parent); | 87 DCHECK(parent); |
| 84 DCHECK(doc); | 88 DCHECK(doc); |
| 85 if (doc->is_folder()) | 89 if (doc->is_folder()) |
| 86 return GDataDirectory::FromDocumentEntry(parent, doc); | 90 return GDataDirectory::FromDocumentEntry(parent, doc); |
| 87 else if (doc->is_hosted_document() || doc->is_file()) | 91 else if (doc->is_hosted_document() || doc->is_file()) |
| 88 return GDataFile::FromDocumentEntry(parent, doc); | 92 return GDataFile::FromDocumentEntry(parent, doc); |
| 89 | 93 |
| 90 return NULL; | 94 return NULL; |
| 91 } | 95 } |
| 92 | 96 |
| 93 // static. | 97 // static. |
| 94 // Escapes forward slashes from file names with magic unicode character \u2215 | |
| 95 // pretty much looks the same in UI. | |
| 96 std::string GDataFileBase::EscapeUtf8FileName(const std::string& input) { | 98 std::string GDataFileBase::EscapeUtf8FileName(const std::string& input) { |
| 97 std::string output; | 99 std::string output; |
| 98 if (ReplaceChars(input, kSlash, std::string(kEscapedSlash), &output)) | 100 if (ReplaceChars(input, kSlash, std::string(kEscapedSlash), &output)) |
| 99 return output; | 101 return output; |
| 100 | 102 |
| 101 return input; | 103 return input; |
| 102 } | 104 } |
| 103 | 105 |
| 104 // static. | 106 // static. |
| 105 // Unescapes what was escaped in EScapeUtf8FileName. | |
| 106 std::string GDataFileBase::UnescapeUtf8FileName(const std::string& input) { | 107 std::string GDataFileBase::UnescapeUtf8FileName(const std::string& input) { |
| 107 std::string output = input; | 108 std::string output = input; |
| 108 ReplaceSubstringsAfterOffset(&output, 0, std::string(kEscapedSlash), kSlash); | 109 ReplaceSubstringsAfterOffset(&output, 0, std::string(kEscapedSlash), kSlash); |
| 109 return output; | 110 return output; |
| 110 } | 111 } |
| 111 | 112 |
| 112 // GDataFile class implementation. | 113 // GDataFile class implementation. |
| 113 | 114 |
| 114 GDataFile::GDataFile(GDataDirectory* parent) | 115 GDataFile::GDataFile(GDataDirectory* parent) |
| 115 : GDataFileBase(parent), | 116 : GDataFileBase(parent), |
| 116 kind_(gdata::DocumentEntry::UNKNOWN), | 117 kind_(gdata::DocumentEntry::UNKNOWN), |
| 117 is_hosted_document_(false) { | 118 is_hosted_document_(false) { |
| 118 DCHECK(parent); | 119 DCHECK(parent); |
| 119 } | 120 } |
| 120 | 121 |
| 121 GDataFile::~GDataFile() { | 122 GDataFile::~GDataFile() { |
| 122 } | 123 } |
| 123 | 124 |
| 124 GDataFile* GDataFile::AsGDataFile() { | 125 GDataFile* GDataFile::AsGDataFile() { |
| 125 return this; | 126 return this; |
| 126 } | 127 } |
| 127 | 128 |
| 129 void GDataFile::SetFileNameFromTitle() { |
| 130 if (is_hosted_document_) { |
| 131 file_name_ = EscapeUtf8FileName(title_ + document_extension_); |
| 132 } else { |
| 133 GDataFileBase::SetFileNameFromTitle(); |
| 134 } |
| 135 } |
| 136 |
| 128 GDataFileBase* GDataFile::FromDocumentEntry(GDataDirectory* parent, | 137 GDataFileBase* GDataFile::FromDocumentEntry(GDataDirectory* parent, |
| 129 DocumentEntry* doc) { | 138 DocumentEntry* doc) { |
| 130 DCHECK(doc->is_hosted_document() || doc->is_file()); | 139 DCHECK(doc->is_hosted_document() || doc->is_file()); |
| 131 GDataFile* file = new GDataFile(parent); | 140 GDataFile* file = new GDataFile(parent); |
| 141 |
| 142 // For regular files, the 'filename' and 'title' attribute in the metadata |
| 143 // may be different (e.g. due to rename). To be consistent with the web |
| 144 // interface and other client to use the 'title' attribute, instead of |
| 145 // 'filename', as the file name in the local snapshot. |
| 146 file->title_ = UTF16ToUTF8(doc->title()); |
| 147 |
| 132 // Check if this entry is a true file, or... | 148 // Check if this entry is a true file, or... |
| 133 if (doc->is_file()) { | 149 if (doc->is_file()) { |
| 134 file->original_file_name_ = UTF16ToUTF8(doc->filename()); | |
| 135 file->file_name_ = | |
| 136 GDataFileBase::EscapeUtf8FileName(file->original_file_name_); | |
| 137 file->file_info_.size = doc->file_size(); | 150 file->file_info_.size = doc->file_size(); |
| 138 file->file_md5_ = doc->file_md5(); | 151 file->file_md5_ = doc->file_md5(); |
| 139 } else { | 152 } else { |
| 140 DCHECK(doc->is_hosted_document()); | |
| 141 // ... a hosted document. | 153 // ... a hosted document. |
| 142 file->original_file_name_ = UTF16ToUTF8(doc->title()); | |
| 143 // Attach .g<something> extension to hosted documents so we can special | 154 // Attach .g<something> extension to hosted documents so we can special |
| 144 // case their handling in UI. | 155 // case their handling in UI. |
| 145 // TODO(zelidrag): Figure out better way how to pass entry info like kind | 156 // TODO(zelidrag): Figure out better way how to pass entry info like kind |
| 146 // to UI through the File API stack. | 157 // to UI through the File API stack. |
| 147 file->file_name_ = GDataFileBase::EscapeUtf8FileName( | 158 file->document_extension_ = doc->GetHostedDocumentExtension(); |
| 148 file->original_file_name_ + doc->GetHostedDocumentExtension()); | |
| 149 // We don't know the size of hosted docs and it does not matter since | 159 // We don't know the size of hosted docs and it does not matter since |
| 150 // is has no effect on the quota. | 160 // is has no effect on the quota. |
| 151 file->file_info_.size = 0; | 161 file->file_info_.size = 0; |
| 152 } | 162 } |
| 153 file->kind_ = doc->kind(); | 163 file->kind_ = doc->kind(); |
| 154 const Link* self_link = doc->GetLinkByType(Link::SELF); | 164 const Link* self_link = doc->GetLinkByType(Link::SELF); |
| 155 if (self_link) | 165 if (self_link) |
| 156 file->self_url_ = self_link->href(); | 166 file->self_url_ = self_link->href(); |
| 157 file->content_url_ = doc->content_url(); | 167 file->content_url_ = doc->content_url(); |
| 158 file->content_mime_type_ = doc->content_mime_type(); | 168 file->content_mime_type_ = doc->content_mime_type(); |
| 159 file->etag_ = doc->etag(); | 169 file->etag_ = doc->etag(); |
| 160 file->resource_id_ = doc->resource_id(); | 170 file->resource_id_ = doc->resource_id(); |
| 161 file->id_ = doc->id(); | 171 file->id_ = doc->id(); |
| 162 file->is_hosted_document_ = doc->is_hosted_document(); | 172 file->is_hosted_document_ = doc->is_hosted_document(); |
| 163 file->file_info_.last_modified = doc->updated_time(); | 173 file->file_info_.last_modified = doc->updated_time(); |
| 164 file->file_info_.last_accessed = doc->updated_time(); | 174 file->file_info_.last_accessed = doc->updated_time(); |
| 165 file->file_info_.creation_time = doc->published_time(); | 175 file->file_info_.creation_time = doc->published_time(); |
| 166 | 176 |
| 177 // SetFileNameFromTitle() must be called after |title_|, |
| 178 // |is_hosted_document_| and |document_extension_| are set. |
| 179 file->SetFileNameFromTitle(); |
| 180 |
| 167 const Link* thumbnail_link = doc->GetLinkByType(Link::THUMBNAIL); | 181 const Link* thumbnail_link = doc->GetLinkByType(Link::THUMBNAIL); |
| 168 if (thumbnail_link) | 182 if (thumbnail_link) |
| 169 file->thumbnail_url_ = thumbnail_link->href(); | 183 file->thumbnail_url_ = thumbnail_link->href(); |
| 170 | 184 |
| 171 const Link* alternate_link = doc->GetLinkByType(Link::ALTERNATE); | 185 const Link* alternate_link = doc->GetLinkByType(Link::ALTERNATE); |
| 172 if (alternate_link) | 186 if (alternate_link) |
| 173 file->edit_url_ = alternate_link->href(); | 187 file->edit_url_ = alternate_link->href(); |
| 174 | 188 |
| 175 return file; | 189 return file; |
| 176 } | 190 } |
| 177 | 191 |
| 178 int GDataFile::GetCacheState() { | 192 int GDataFile::GetCacheState() { |
| 179 return root_->GetCacheState(resource(), file_md5()); | 193 return root_->GetCacheState(resource_id(), file_md5()); |
| 180 } | 194 } |
| 181 | 195 |
| 182 // GDataDirectory class implementation. | 196 // GDataDirectory class implementation. |
| 183 | 197 |
| 184 GDataDirectory::GDataDirectory(GDataDirectory* parent) | 198 GDataDirectory::GDataDirectory(GDataDirectory* parent) |
| 185 : GDataFileBase(parent) { | 199 : GDataFileBase(parent) { |
| 186 file_info_.is_directory = true; | 200 file_info_.is_directory = true; |
| 187 } | 201 } |
| 188 | 202 |
| 189 GDataDirectory::~GDataDirectory() { | 203 GDataDirectory::~GDataDirectory() { |
| 190 RemoveChildren(); | 204 RemoveChildren(); |
| 191 } | 205 } |
| 192 | 206 |
| 193 GDataDirectory* GDataDirectory::AsGDataDirectory() { | 207 GDataDirectory* GDataDirectory::AsGDataDirectory() { |
| 194 return this; | 208 return this; |
| 195 } | 209 } |
| 196 | 210 |
| 197 // static | 211 // static |
| 198 GDataFileBase* GDataDirectory::FromDocumentEntry(GDataDirectory* parent, | 212 GDataFileBase* GDataDirectory::FromDocumentEntry(GDataDirectory* parent, |
| 199 DocumentEntry* doc) { | 213 DocumentEntry* doc) { |
| 200 DCHECK(parent); | 214 DCHECK(parent); |
| 201 DCHECK(doc->is_folder()); | 215 DCHECK(doc->is_folder()); |
| 202 GDataDirectory* dir = new GDataDirectory(parent); | 216 GDataDirectory* dir = new GDataDirectory(parent); |
| 203 dir->original_file_name_ = UTF16ToUTF8(doc->title()); | 217 dir->title_ = UTF16ToUTF8(doc->title()); |
| 204 dir->file_name_ = GDataFileBase::EscapeUtf8FileName(dir->original_file_name_); | 218 // SetFileNameFromTitle() must be called after |title_| is set. |
| 219 dir->SetFileNameFromTitle(); |
| 205 dir->file_info_.last_modified = doc->updated_time(); | 220 dir->file_info_.last_modified = doc->updated_time(); |
| 206 dir->file_info_.last_accessed = doc->updated_time(); | 221 dir->file_info_.last_accessed = doc->updated_time(); |
| 207 dir->file_info_.creation_time = doc->published_time(); | 222 dir->file_info_.creation_time = doc->published_time(); |
| 208 // Extract feed link. | 223 // Extract feed link. |
| 209 dir->start_feed_url_ = doc->content_url(); | 224 dir->start_feed_url_ = doc->content_url(); |
| 225 dir->resource_id_ = doc->resource_id(); |
| 210 dir->content_url_ = doc->content_url(); | 226 dir->content_url_ = doc->content_url(); |
| 211 | 227 |
| 228 const Link* self_link = doc->GetLinkByType(Link::SELF); |
| 229 if (self_link) |
| 230 dir->self_url_ = self_link->href(); |
| 231 |
| 212 const Link* upload_link = doc->GetLinkByType(Link::RESUMABLE_CREATE_MEDIA); | 232 const Link* upload_link = doc->GetLinkByType(Link::RESUMABLE_CREATE_MEDIA); |
| 213 if (upload_link) | 233 if (upload_link) |
| 214 dir->upload_url_ = upload_link->href(); | 234 dir->upload_url_ = upload_link->href(); |
| 215 | 235 |
| 216 return dir; | 236 return dir; |
| 217 } | 237 } |
| 218 | 238 |
| 219 void GDataDirectory::RemoveChildren() { | 239 void GDataDirectory::RemoveChildren() { |
| 220 // Remove children from resource map first. | 240 // Remove children from resource map first. |
| 221 root_->RemoveFilesFromResourceMap(children_); | 241 root_->RemoveFilesFromResourceMap(children_); |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 253 } | 273 } |
| 254 } | 274 } |
| 255 if (full_file_name.value() != file->file_name()) | 275 if (full_file_name.value() != file->file_name()) |
| 256 file->set_file_name(full_file_name.value()); | 276 file->set_file_name(full_file_name.value()); |
| 257 children_.insert(std::make_pair(file->file_name(), file)); | 277 children_.insert(std::make_pair(file->file_name(), file)); |
| 258 | 278 |
| 259 // Add file to resource map. | 279 // Add file to resource map. |
| 260 root_->AddFileToResourceMap(file); | 280 root_->AddFileToResourceMap(file); |
| 261 } | 281 } |
| 262 | 282 |
| 283 bool GDataDirectory::TakeFile(GDataFileBase* file) { |
| 284 DCHECK(file); |
| 285 DCHECK(file->parent()); |
| 286 |
| 287 file->parent()->RemoveFileFromChildrenList(file); |
| 288 |
| 289 // The file name may have been changed due to prior name de-duplication. |
| 290 // We need to first restore the file name based on the title before going |
| 291 // through name de-duplication again when it is added to another directory. |
| 292 file->SetFileNameFromTitle(); |
| 293 AddFile(file); |
| 294 |
| 295 // Use GDataFileBase::set_parent() to change the parent of GDataFileBase |
| 296 // as GDataDirectory:AddFile() does not do that. |
| 297 file->set_parent(this); |
| 298 return true; |
| 299 } |
| 300 |
| 263 bool GDataDirectory::RemoveFile(GDataFileBase* file) { | 301 bool GDataDirectory::RemoveFile(GDataFileBase* file) { |
| 302 DCHECK(file); |
| 303 |
| 304 if (!RemoveFileFromChildrenList(file)) |
| 305 return false; |
| 306 |
| 307 delete file; |
| 308 return true; |
| 309 } |
| 310 |
| 311 bool GDataDirectory::RemoveFileFromChildrenList(GDataFileBase* file) { |
| 312 DCHECK(file); |
| 313 |
| 264 GDataFileCollection::iterator iter = children_.find(file->file_name()); | 314 GDataFileCollection::iterator iter = children_.find(file->file_name()); |
| 265 if (iter == children_.end()) | 315 if (iter == children_.end()) |
| 266 return false; | 316 return false; |
| 267 | 317 |
| 268 DCHECK(iter->second); | 318 DCHECK(iter->second); |
| 319 DCHECK_EQ(file, iter->second); |
| 269 | 320 |
| 270 // Remove file from resource map first. | 321 // Remove file from resource map first. |
| 271 root_->RemoveFileFromResourceMap(file); | 322 root_->RemoveFileFromResourceMap(file); |
| 272 | 323 |
| 273 // Then delete it from tree. | 324 // Then delete it from tree. |
| 274 delete iter->second; | |
| 275 children_.erase(iter); | 325 children_.erase(iter); |
| 276 | 326 |
| 277 return true; | 327 return true; |
| 278 } | 328 } |
| 279 | 329 |
| 280 // GDataRootDirectory class implementation. | 330 // GDataRootDirectory class implementation. |
| 281 | 331 |
| 282 GDataRootDirectory::GDataRootDirectory() | 332 GDataRootDirectory::GDataRootDirectory() |
| 283 : GDataDirectory(NULL) { | 333 : GDataDirectory(NULL) { |
| 284 root_ = this; | 334 root_ = this; |
| 285 } | 335 } |
| 286 | 336 |
| 287 GDataRootDirectory::~GDataRootDirectory() { | 337 GDataRootDirectory::~GDataRootDirectory() { |
| 288 STLDeleteValues(&cache_map_); | 338 STLDeleteValues(&cache_map_); |
| 289 cache_map_.clear(); | 339 cache_map_.clear(); |
| 290 | 340 |
| 291 resource_map_.clear(); | 341 resource_map_.clear(); |
| 292 } | 342 } |
| 293 | 343 |
| 294 GDataRootDirectory* GDataRootDirectory::AsGDataRootDirectory() { | 344 GDataRootDirectory* GDataRootDirectory::AsGDataRootDirectory() { |
| 295 return this; | 345 return this; |
| 296 } | 346 } |
| 297 | 347 |
| 298 void GDataRootDirectory::AddFileToResourceMap(GDataFileBase* file) { | 348 void GDataRootDirectory::AddFileToResourceMap(GDataFileBase* file) { |
| 299 // GDataFileSystem has already locked. | 349 // GDataFileSystem has already locked. |
| 300 // Only files have resource. | 350 // Only files have resource. |
| 301 if (file->AsGDataFile()) { | 351 if (file->AsGDataFile()) { |
| 302 resource_map_.insert( | 352 resource_map_.insert( |
| 303 std::make_pair(file->AsGDataFile()->resource(), file)); | 353 std::make_pair(file->AsGDataFile()->resource_id(), file)); |
| 304 } | 354 } |
| 305 } | 355 } |
| 306 | 356 |
| 307 void GDataRootDirectory::RemoveFileFromResourceMap(GDataFileBase* file) { | 357 void GDataRootDirectory::RemoveFileFromResourceMap(GDataFileBase* file) { |
| 308 // GDataFileSystem has already locked. | 358 // GDataFileSystem has already locked. |
| 309 if (file->AsGDataFile()) | 359 if (file->AsGDataFile()) |
| 310 resource_map_.erase(file->AsGDataFile()->resource()); | 360 resource_map_.erase(file->AsGDataFile()->resource_id()); |
| 311 } | 361 } |
| 312 | 362 |
| 313 void GDataRootDirectory::RemoveFilesFromResourceMap( | 363 void GDataRootDirectory::RemoveFilesFromResourceMap( |
| 314 const GDataFileCollection& children) { | 364 const GDataFileCollection& children) { |
| 315 // GDataFileSystem has already locked. | 365 // GDataFileSystem has already locked. |
| 316 for (GDataFileCollection::const_iterator iter = children.begin(); | 366 for (GDataFileCollection::const_iterator iter = children.begin(); |
| 317 iter != children.end(); ++iter) { | 367 iter != children.end(); ++iter) { |
| 318 // Recursively call RemoveFilesFromResourceMap for each directory. | 368 // Recursively call RemoveFilesFromResourceMap for each directory. |
| 319 if (iter->second->AsGDataDirectory()) { | 369 if (iter->second->AsGDataDirectory()) { |
| 320 RemoveFilesFromResourceMap(iter->second->AsGDataDirectory()->children()); | 370 RemoveFilesFromResourceMap(iter->second->AsGDataDirectory()->children()); |
| 321 continue; | 371 continue; |
| 322 } | 372 } |
| 323 | 373 |
| 324 // Only files have resource. | 374 // Only files have resource. |
| 325 if (iter->second->AsGDataFile()) | 375 if (iter->second->AsGDataFile()) |
| 326 resource_map_.erase(iter->second->AsGDataFile()->resource()); | 376 resource_map_.erase(iter->second->AsGDataFile()->resource_id()); |
| 327 } | 377 } |
| 328 } | 378 } |
| 329 | 379 |
| 330 GDataFileBase* GDataRootDirectory::GetFileByResource( | 380 GDataFileBase* GDataRootDirectory::GetFileByResource( |
| 331 const std::string& resource) { | 381 const std::string& resource) { |
| 332 // GDataFileSystem has already locked. | 382 // GDataFileSystem has already locked. |
| 333 ResourceMap::const_iterator iter = resource_map_.find(resource); | 383 ResourceMap::const_iterator iter = resource_map_.find(resource); |
| 334 if (iter == resource_map_.end()) | 384 if (iter == resource_map_.end()) |
| 335 return NULL; | 385 return NULL; |
| 336 return iter->second; | 386 return iter->second; |
| (...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 418 cache_state |= GDataFile::CACHE_STATE_PINNED; | 468 cache_state |= GDataFile::CACHE_STATE_PINNED; |
| 419 | 469 |
| 420 DVLOG(1) << "Cache state for res_id " << res_id | 470 DVLOG(1) << "Cache state for res_id " << res_id |
| 421 << ", md5 " << entry->md5 | 471 << ", md5 " << entry->md5 |
| 422 << ": " << cache_state; | 472 << ": " << cache_state; |
| 423 | 473 |
| 424 return cache_state; | 474 return cache_state; |
| 425 } | 475 } |
| 426 | 476 |
| 427 } // namespace gdata | 477 } // namespace gdata |
| OLD | NEW |