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::UseOriginalFileName() { |
| 81 file_name_ = EscapeUtf8FileName(original_file_name_); |
| 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::UseOriginalFileName() { |
| 130 if (is_hosted_document_) { |
| 131 file_name_ = EscapeUtf8FileName(original_file_name_ + document_extension_); |
| 132 } else { |
| 133 GDataFileBase::UseOriginalFileName(); |
| 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->original_file_name_ = 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 // UseOriginalFileName() must be called after |is_hosted_document_| and |
| 178 // |document_extension_| are properly set. |
| 179 file->UseOriginalFileName(); |
| 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->original_file_name_ = UTF16ToUTF8(doc->title()); |
204 dir->file_name_ = GDataFileBase::EscapeUtf8FileName(dir->original_file_name_); | 218 dir->UseOriginalFileName(); |
205 dir->file_info_.last_modified = doc->updated_time(); | 219 dir->file_info_.last_modified = doc->updated_time(); |
206 dir->file_info_.last_accessed = doc->updated_time(); | 220 dir->file_info_.last_accessed = doc->updated_time(); |
207 dir->file_info_.creation_time = doc->published_time(); | 221 dir->file_info_.creation_time = doc->published_time(); |
208 // Extract feed link. | 222 // Extract feed link. |
209 dir->start_feed_url_ = doc->content_url(); | 223 dir->start_feed_url_ = doc->content_url(); |
| 224 dir->resource_id_ = doc->resource_id(); |
210 dir->content_url_ = doc->content_url(); | 225 dir->content_url_ = doc->content_url(); |
211 | 226 |
| 227 const Link* self_link = doc->GetLinkByType(Link::SELF); |
| 228 if (self_link) |
| 229 dir->self_url_ = self_link->href(); |
| 230 |
212 const Link* upload_link = doc->GetLinkByType(Link::RESUMABLE_CREATE_MEDIA); | 231 const Link* upload_link = doc->GetLinkByType(Link::RESUMABLE_CREATE_MEDIA); |
213 if (upload_link) | 232 if (upload_link) |
214 dir->upload_url_ = upload_link->href(); | 233 dir->upload_url_ = upload_link->href(); |
215 | 234 |
216 return dir; | 235 return dir; |
217 } | 236 } |
218 | 237 |
219 void GDataDirectory::RemoveChildren() { | 238 void GDataDirectory::RemoveChildren() { |
220 // Remove children from resource map first. | 239 // Remove children from resource map first. |
221 root_->RemoveFilesFromResourceMap(children_); | 240 root_->RemoveFilesFromResourceMap(children_); |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
253 } | 272 } |
254 } | 273 } |
255 if (full_file_name.value() != file->file_name()) | 274 if (full_file_name.value() != file->file_name()) |
256 file->set_file_name(full_file_name.value()); | 275 file->set_file_name(full_file_name.value()); |
257 children_.insert(std::make_pair(file->file_name(), file)); | 276 children_.insert(std::make_pair(file->file_name(), file)); |
258 | 277 |
259 // Add file to resource map. | 278 // Add file to resource map. |
260 root_->AddFileToResourceMap(file); | 279 root_->AddFileToResourceMap(file); |
261 } | 280 } |
262 | 281 |
| 282 bool GDataDirectory::TakeFile(GDataFileBase* file) { |
| 283 DCHECK(file); |
| 284 DCHECK(file->parent()); |
| 285 |
| 286 file->parent()->RemoveFileFromChildrenList(file); |
| 287 |
| 288 // The file name may have been changed due to prior de-duplication. |
| 289 // We need to first restore the original name of the file before going |
| 290 // through de-duplication again when it is added to another directory |
| 291 file->UseOriginalFileName(); |
| 292 AddFile(file); |
| 293 |
| 294 // Use GDataFileBase::set_parent() to change the parent of GDataFileBase |
| 295 // as GDataDirectory:AddFile() does not do that. |
| 296 file->set_parent(this); |
| 297 return true; |
| 298 } |
| 299 |
263 bool GDataDirectory::RemoveFile(GDataFileBase* file) { | 300 bool GDataDirectory::RemoveFile(GDataFileBase* file) { |
| 301 DCHECK(file); |
| 302 |
| 303 if (!RemoveFileFromChildrenList(file)) |
| 304 return false; |
| 305 |
| 306 delete file; |
| 307 return true; |
| 308 } |
| 309 |
| 310 bool GDataDirectory::RemoveFileFromChildrenList(GDataFileBase* file) { |
| 311 DCHECK(file); |
| 312 |
264 GDataFileCollection::iterator iter = children_.find(file->file_name()); | 313 GDataFileCollection::iterator iter = children_.find(file->file_name()); |
265 if (iter == children_.end()) | 314 if (iter == children_.end()) |
266 return false; | 315 return false; |
267 | 316 |
268 DCHECK(iter->second); | 317 DCHECK(iter->second); |
| 318 DCHECK_EQ(file, iter->second); |
269 | 319 |
270 // Remove file from resource map first. | 320 // Remove file from resource map first. |
271 root_->RemoveFileFromResourceMap(file); | 321 root_->RemoveFileFromResourceMap(file); |
272 | 322 |
273 // Then delete it from tree. | 323 // Then delete it from tree. |
274 delete iter->second; | |
275 children_.erase(iter); | 324 children_.erase(iter); |
276 | 325 |
277 return true; | 326 return true; |
278 } | 327 } |
279 | 328 |
280 // GDataRootDirectory class implementation. | 329 // GDataRootDirectory class implementation. |
281 | 330 |
282 GDataRootDirectory::GDataRootDirectory() | 331 GDataRootDirectory::GDataRootDirectory() |
283 : GDataDirectory(NULL) { | 332 : GDataDirectory(NULL) { |
284 root_ = this; | 333 root_ = this; |
285 } | 334 } |
286 | 335 |
287 GDataRootDirectory::~GDataRootDirectory() { | 336 GDataRootDirectory::~GDataRootDirectory() { |
288 STLDeleteValues(&cache_map_); | 337 STLDeleteValues(&cache_map_); |
289 cache_map_.clear(); | 338 cache_map_.clear(); |
290 | 339 |
291 resource_map_.clear(); | 340 resource_map_.clear(); |
292 } | 341 } |
293 | 342 |
294 GDataRootDirectory* GDataRootDirectory::AsGDataRootDirectory() { | 343 GDataRootDirectory* GDataRootDirectory::AsGDataRootDirectory() { |
295 return this; | 344 return this; |
296 } | 345 } |
297 | 346 |
298 void GDataRootDirectory::AddFileToResourceMap(GDataFileBase* file) { | 347 void GDataRootDirectory::AddFileToResourceMap(GDataFileBase* file) { |
299 // GDataFileSystem has already locked. | 348 // GDataFileSystem has already locked. |
300 // Only files have resource. | 349 // Only files have resource. |
301 if (file->AsGDataFile()) { | 350 if (file->AsGDataFile()) { |
302 resource_map_.insert( | 351 resource_map_.insert( |
303 std::make_pair(file->AsGDataFile()->resource(), file)); | 352 std::make_pair(file->AsGDataFile()->resource_id(), file)); |
304 } | 353 } |
305 } | 354 } |
306 | 355 |
307 void GDataRootDirectory::RemoveFileFromResourceMap(GDataFileBase* file) { | 356 void GDataRootDirectory::RemoveFileFromResourceMap(GDataFileBase* file) { |
308 // GDataFileSystem has already locked. | 357 // GDataFileSystem has already locked. |
309 if (file->AsGDataFile()) | 358 if (file->AsGDataFile()) |
310 resource_map_.erase(file->AsGDataFile()->resource()); | 359 resource_map_.erase(file->AsGDataFile()->resource_id()); |
311 } | 360 } |
312 | 361 |
313 void GDataRootDirectory::RemoveFilesFromResourceMap( | 362 void GDataRootDirectory::RemoveFilesFromResourceMap( |
314 const GDataFileCollection& children) { | 363 const GDataFileCollection& children) { |
315 // GDataFileSystem has already locked. | 364 // GDataFileSystem has already locked. |
316 for (GDataFileCollection::const_iterator iter = children.begin(); | 365 for (GDataFileCollection::const_iterator iter = children.begin(); |
317 iter != children.end(); ++iter) { | 366 iter != children.end(); ++iter) { |
318 // Recursively call RemoveFilesFromResourceMap for each directory. | 367 // Recursively call RemoveFilesFromResourceMap for each directory. |
319 if (iter->second->AsGDataDirectory()) { | 368 if (iter->second->AsGDataDirectory()) { |
320 RemoveFilesFromResourceMap(iter->second->AsGDataDirectory()->children()); | 369 RemoveFilesFromResourceMap(iter->second->AsGDataDirectory()->children()); |
321 continue; | 370 continue; |
322 } | 371 } |
323 | 372 |
324 // Only files have resource. | 373 // Only files have resource. |
325 if (iter->second->AsGDataFile()) | 374 if (iter->second->AsGDataFile()) |
326 resource_map_.erase(iter->second->AsGDataFile()->resource()); | 375 resource_map_.erase(iter->second->AsGDataFile()->resource_id()); |
327 } | 376 } |
328 } | 377 } |
329 | 378 |
330 GDataFileBase* GDataRootDirectory::GetFileByResource( | 379 GDataFileBase* GDataRootDirectory::GetFileByResource( |
331 const std::string& resource) { | 380 const std::string& resource) { |
332 // GDataFileSystem has already locked. | 381 // GDataFileSystem has already locked. |
333 ResourceMap::const_iterator iter = resource_map_.find(resource); | 382 ResourceMap::const_iterator iter = resource_map_.find(resource); |
334 if (iter == resource_map_.end()) | 383 if (iter == resource_map_.end()) |
335 return NULL; | 384 return NULL; |
336 return iter->second; | 385 return iter->second; |
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
418 cache_state |= GDataFile::CACHE_STATE_PINNED; | 467 cache_state |= GDataFile::CACHE_STATE_PINNED; |
419 | 468 |
420 DVLOG(1) << "Cache state for res_id " << res_id | 469 DVLOG(1) << "Cache state for res_id " << res_id |
421 << ", md5 " << entry->md5 | 470 << ", md5 " << entry->md5 |
422 << ": " << cache_state; | 471 << ": " << cache_state; |
423 | 472 |
424 return cache_state; | 473 return cache_state; |
425 } | 474 } |
426 | 475 |
427 } // namespace gdata | 476 } // namespace gdata |
OLD | NEW |