OLD | NEW |
1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2006-2008 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/download/save_package.h" | 5 #include "chrome/browser/download/save_package.h" |
6 | 6 |
7 #include "base/file_util.h" | 7 #include "base/file_util.h" |
8 #include "base/logging.h" | 8 #include "base/logging.h" |
9 #include "base/message_loop.h" | 9 #include "base/message_loop.h" |
10 #include "base/path_service.h" | 10 #include "base/path_service.h" |
(...skipping 25 matching lines...) Expand all Loading... |
36 #include "net/base/net_util.h" | 36 #include "net/base/net_util.h" |
37 #include "net/url_request/url_request_context.h" | 37 #include "net/url_request/url_request_context.h" |
38 #include "webkit/glue/dom_serializer_delegate.h" | 38 #include "webkit/glue/dom_serializer_delegate.h" |
39 | 39 |
40 #include "generated_resources.h" | 40 #include "generated_resources.h" |
41 | 41 |
42 using base::Time; | 42 using base::Time; |
43 | 43 |
44 namespace { | 44 namespace { |
45 | 45 |
| 46 const FilePath::CharType kLeftParen = FILE_PATH_LITERAL('('); |
| 47 const FilePath::CharType kRightParen = FILE_PATH_LITERAL(')'); |
| 48 |
46 // Default name which will be used when we can not get proper name from | 49 // Default name which will be used when we can not get proper name from |
47 // resource URL. | 50 // resource URL. |
48 const wchar_t kDefaultSaveName[] = L"saved_resource"; | 51 const wchar_t kDefaultSaveName[] = L"saved_resource"; |
49 | 52 |
50 // Maximum number of file ordinal number. I think it's big enough for resolving | 53 // Maximum number of file ordinal number. I think it's big enough for resolving |
51 // name-conflict files which has same base file name. | 54 // name-conflict files which has same base file name. |
52 const int32 kMaxFileOrdinalNumber = 9999; | 55 const int32 kMaxFileOrdinalNumber = 9999; |
53 | 56 |
54 // Maximum length for file path. Since Windows have MAX_PATH limitation for | 57 // Maximum length for file path. Since Windows have MAX_PATH limitation for |
55 // file path, we need to make sure length of file path of every saved file | 58 // file path, we need to make sure length of file path of every saved file |
56 // is less than MAX_PATH | 59 // is less than MAX_PATH |
57 const uint32 kMaxFilePathLength = MAX_PATH - 1; | 60 const uint32 kMaxFilePathLength = MAX_PATH - 1; |
58 | 61 |
59 // Maximum length for file ordinal number part. Since we only support the | 62 // Maximum length for file ordinal number part. Since we only support the |
60 // maximum 9999 for ordinal number, which means maximum file ordinal number part | 63 // maximum 9999 for ordinal number, which means maximum file ordinal number part |
61 // should be "(9998)", so the value is 6. | 64 // should be "(9998)", so the value is 6. |
62 const uint32 kMaxFileOrdinalNumberPartLength = 6; | 65 const uint32 kMaxFileOrdinalNumberPartLength = 6; |
63 | 66 |
64 // If false, we don't prompt the user as to where to save the file. This | 67 // If false, we don't prompt the user as to where to save the file. This |
65 // exists only for testing. | 68 // exists only for testing. |
66 bool g_should_prompt_for_filename = true; | 69 bool g_should_prompt_for_filename = true; |
67 | 70 |
| 71 // Strip current ordinal number, if any. Should only be used on pure |
| 72 // file names, i.e. those stripped of their extensions. |
| 73 // TODO(estade): improve this to not choke on alternate encodings. |
| 74 FilePath::StringType StripOrdinalNumber( |
| 75 const FilePath::StringType& pure_file_name) { |
| 76 FilePath::StringType::size_type r_paren_index = |
| 77 pure_file_name.rfind(FILE_PATH_LITERAL(')')); |
| 78 FilePath::StringType::size_type l_paren_index = |
| 79 pure_file_name.rfind(FILE_PATH_LITERAL('(')); |
| 80 if (l_paren_index >= r_paren_index) |
| 81 return pure_file_name; |
| 82 |
| 83 for (FilePath::StringType::size_type i = l_paren_index + 1; |
| 84 i != r_paren_index; ++i) { |
| 85 if (!IsAsciiDigit(pure_file_name[i])) |
| 86 return pure_file_name; |
| 87 } |
| 88 |
| 89 return pure_file_name.substr(0, l_paren_index); |
| 90 } |
| 91 |
68 } // namespace | 92 } // namespace |
69 | 93 |
70 SavePackage::SavePackage(WebContents* web_content, | 94 SavePackage::SavePackage(WebContents* web_content, |
71 SavePackageType save_type, | 95 SavePackageType save_type, |
72 const std::wstring& file_full_path, | 96 const FilePath& file_full_path, |
73 const std::wstring& directory_full_path) | 97 const FilePath& directory_full_path) |
74 : web_contents_(web_content), | 98 : web_contents_(web_content), |
75 save_type_(save_type), | 99 save_type_(save_type), |
76 saved_main_file_path_(file_full_path), | 100 saved_main_file_path_(file_full_path), |
77 saved_main_directory_path_(directory_full_path), | 101 saved_main_directory_path_(directory_full_path), |
78 all_save_items_count_(0), | 102 all_save_items_count_(0), |
79 disk_error_occurred_(false), | 103 disk_error_occurred_(false), |
80 user_canceled_(false), | 104 user_canceled_(false), |
81 download_(NULL), | 105 download_(NULL), |
82 finished_(false), | 106 finished_(false), |
83 wait_state_(INITIALIZE), | 107 wait_state_(INITIALIZE), |
84 tab_id_(web_content->process()->host_id()) { | 108 tab_id_(web_content->process()->host_id()) { |
85 DCHECK(web_content); | 109 DCHECK(web_content); |
86 const GURL& current_page_url = web_contents_->GetURL(); | 110 const GURL& current_page_url = web_contents_->GetURL(); |
87 DCHECK(current_page_url.is_valid()); | 111 DCHECK(current_page_url.is_valid()); |
88 page_url_ = UTF8ToWide(current_page_url.spec()); | 112 page_url_ = UTF8ToWide(current_page_url.spec()); |
89 DCHECK(save_type_ == SAVE_AS_ONLY_HTML || | 113 DCHECK(save_type_ == SAVE_AS_ONLY_HTML || |
90 save_type_ == SAVE_AS_COMPLETE_HTML); | 114 save_type_ == SAVE_AS_COMPLETE_HTML); |
91 DCHECK(!saved_main_file_path_.empty() && | 115 DCHECK(!saved_main_file_path_.empty() && |
92 saved_main_file_path_.length() <= kMaxFilePathLength); | 116 saved_main_file_path_.value().length() <= kMaxFilePathLength); |
93 DCHECK(!saved_main_directory_path_.empty() && | 117 DCHECK(!saved_main_directory_path_.empty() && |
94 saved_main_directory_path_.length() < kMaxFilePathLength); | 118 saved_main_directory_path_.value().length() < kMaxFilePathLength); |
95 } | 119 } |
96 | 120 |
97 // This is for testing use. Set |finished_| as true because we don't want | 121 // This is for testing use. Set |finished_| as true because we don't want |
98 // method Cancel to be be called in destructor in test mode. | 122 // method Cancel to be be called in destructor in test mode. |
99 SavePackage::SavePackage(const wchar_t* file_full_path, | 123 SavePackage::SavePackage(const FilePath::CharType* file_full_path, |
100 const wchar_t* directory_full_path) | 124 const FilePath::CharType* directory_full_path) |
101 : all_save_items_count_(0), | 125 : all_save_items_count_(0), |
102 saved_main_file_path_(file_full_path), | 126 saved_main_file_path_(file_full_path), |
103 saved_main_directory_path_(directory_full_path), | 127 saved_main_directory_path_(directory_full_path), |
104 finished_(true), | 128 finished_(true), |
105 download_(NULL), | 129 download_(NULL), |
106 user_canceled_(false), | 130 user_canceled_(false), |
107 disk_error_occurred_(false), | 131 disk_error_occurred_(false), |
108 tab_id_(0) { | 132 tab_id_(0) { |
109 DCHECK(!saved_main_file_path_.empty() && | 133 DCHECK(!saved_main_file_path_.empty() && |
110 saved_main_file_path_.length() <= kMaxFilePathLength); | 134 saved_main_file_path_.value().length() <= kMaxFilePathLength); |
111 DCHECK(!saved_main_directory_path_.empty() && | 135 DCHECK(!saved_main_directory_path_.empty() && |
112 saved_main_directory_path_.length() < kMaxFilePathLength); | 136 saved_main_directory_path_.value().length() < kMaxFilePathLength); |
113 } | 137 } |
114 | 138 |
115 SavePackage::~SavePackage() { | 139 SavePackage::~SavePackage() { |
116 // Stop receiving saving job's updates | 140 // Stop receiving saving job's updates |
117 if (!finished_ && !canceled()) { | 141 if (!finished_ && !canceled()) { |
118 // Unexpected quit. | 142 // Unexpected quit. |
119 Cancel(true); | 143 Cancel(true); |
120 } | 144 } |
121 | 145 |
122 DCHECK(all_save_items_count_ == (waiting_item_queue_.size() + | 146 DCHECK(all_save_items_count_ == (waiting_item_queue_.size() + |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
179 return false; | 203 return false; |
180 } | 204 } |
181 | 205 |
182 file_manager_ = rdh->save_file_manager(); | 206 file_manager_ = rdh->save_file_manager(); |
183 if (!file_manager_) { | 207 if (!file_manager_) { |
184 NOTREACHED(); | 208 NOTREACHED(); |
185 return false; | 209 return false; |
186 } | 210 } |
187 | 211 |
188 // Create the fake DownloadItem and display the view. | 212 // Create the fake DownloadItem and display the view. |
189 download_ = new DownloadItem(1, | 213 download_ = new DownloadItem(1, saved_main_file_path_, 0, page_url_, |
190 FilePath::FromWStringHack(saved_main_file_path_), 0, page_url_, | |
191 FilePath(), Time::Now(), 0, -1, -1, false); | 214 FilePath(), Time::Now(), 0, -1, -1, false); |
192 download_->set_manager(web_contents_->profile()->GetDownloadManager()); | 215 download_->set_manager(web_contents_->profile()->GetDownloadManager()); |
193 DownloadShelfView* shelf = web_contents_->GetDownloadShelfView(); | 216 DownloadShelfView* shelf = web_contents_->GetDownloadShelfView(); |
194 shelf->AddDownloadView(new DownloadItemView( | 217 shelf->AddDownloadView(new DownloadItemView( |
195 download_, shelf, new SavePageModel(this, download_))); | 218 download_, shelf, new SavePageModel(this, download_))); |
196 web_contents_->SetDownloadShelfVisible(true); | 219 web_contents_->SetDownloadShelfVisible(true); |
197 | 220 |
198 // Check save type and process the save page job. | 221 // Check save type and process the save page job. |
199 if (save_type_ == SAVE_AS_COMPLETE_HTML) { | 222 if (save_type_ == SAVE_AS_COMPLETE_HTML) { |
200 // Get directory | 223 // Get directory |
(...skipping 15 matching lines...) Expand all Loading... |
216 download_->set_total_bytes(1); | 239 download_->set_total_bytes(1); |
217 | 240 |
218 DoSavingProcess(); | 241 DoSavingProcess(); |
219 } | 242 } |
220 | 243 |
221 return true; | 244 return true; |
222 } | 245 } |
223 | 246 |
224 // Generate name for saving resource. | 247 // Generate name for saving resource. |
225 bool SavePackage::GenerateFilename(const std::string& disposition, | 248 bool SavePackage::GenerateFilename(const std::string& disposition, |
226 const std::wstring& url, | 249 const GURL& url, |
227 bool need_html_ext, | 250 bool need_html_ext, |
228 std::wstring* generated_name) { | 251 FilePath::StringType* generated_name) { |
229 std::wstring file_name = | 252 FilePath file_path = FilePath::FromWStringHack( |
230 net::GetSuggestedFilename(GURL(url), disposition, kDefaultSaveName); | 253 net::GetSuggestedFilename(url, disposition, kDefaultSaveName)); |
231 | 254 |
232 DCHECK(!file_name.empty()); | 255 DCHECK(!file_path.empty()); |
233 // Check whether we have same name before. | 256 FilePath::StringType pure_file_name = |
234 std::wstring::size_type last_dot = file_name.rfind(L'.'); | 257 file_path.RemoveExtension().BaseName().value(); |
235 std::wstring pure_file_name, file_name_ext; | 258 FilePath::StringType file_name_ext = file_path.Extension(); |
236 if (last_dot == std::wstring::npos) { | 259 |
237 pure_file_name = file_name; | |
238 } else { | |
239 pure_file_name = std::wstring(file_name, 0, last_dot); | |
240 file_name_ext = std::wstring(file_name, last_dot); | |
241 } | |
242 // If it is HTML resource, use ".htm" as its extension name. | 260 // If it is HTML resource, use ".htm" as its extension name. |
243 if (need_html_ext) | 261 if (need_html_ext) |
244 file_name_ext = L".htm"; | 262 file_name_ext = FILE_PATH_LITERAL(".htm"); |
245 if (file_name_ext == L".") | |
246 file_name_ext.clear(); | |
247 | 263 |
248 // Get safe pure file name. | 264 // Get safe pure file name. |
249 if (!GetSafePureFileName(saved_main_directory_path_, file_name_ext, | 265 if (!GetSafePureFileName(saved_main_directory_path_, file_name_ext, |
250 kMaxFilePathLength, &pure_file_name)) | 266 kMaxFilePathLength, &pure_file_name)) |
251 return false; | 267 return false; |
252 | 268 |
253 file_name = pure_file_name + file_name_ext; | 269 FilePath::StringType file_name = pure_file_name + file_name_ext; |
254 | 270 |
255 // Check whether we already have same name. | 271 // Check whether we already have same name. |
256 if (file_name_set_.find(file_name) == file_name_set_.end()) { | 272 if (file_name_set_.find(file_name) == file_name_set_.end()) { |
257 file_name_set_.insert(file_name); | 273 file_name_set_.insert(file_name); |
258 } else { | 274 } else { |
259 // Found same name, increase the ordinal number for the file name. | 275 // Found same name, increase the ordinal number for the file name. |
260 std::wstring base_file_name, file_ordinal_number; | 276 FilePath::StringType base_file_name = StripOrdinalNumber(pure_file_name); |
261 | |
262 if (!GetBaseFileNameAndFileOrdinalNumber(pure_file_name, &base_file_name, | |
263 &file_ordinal_number)) | |
264 base_file_name = pure_file_name; | |
265 | 277 |
266 // We need to make sure the length of base file name plus maximum ordinal | 278 // We need to make sure the length of base file name plus maximum ordinal |
267 // number path will be less than or equal to kMaxFilePathLength. | 279 // number path will be less than or equal to kMaxFilePathLength. |
268 if (!GetSafePureFileName(saved_main_directory_path_, file_name_ext, | 280 if (!GetSafePureFileName(saved_main_directory_path_, file_name_ext, |
269 kMaxFilePathLength - kMaxFileOrdinalNumberPartLength, &base_file_name)) | 281 kMaxFilePathLength - kMaxFileOrdinalNumberPartLength, &base_file_name)) |
270 return false; | 282 return false; |
271 | 283 |
272 // Prepare the new ordinal number. | 284 // Prepare the new ordinal number. |
273 uint32 ordinal_number; | 285 uint32 ordinal_number; |
274 FileNameCountMap::iterator it = file_name_count_map_.find(base_file_name); | 286 FileNameCountMap::iterator it = file_name_count_map_.find(base_file_name); |
275 if (it == file_name_count_map_.end()) { | 287 if (it == file_name_count_map_.end()) { |
276 // First base-name-conflict resolving, use 1 as initial ordinal number. | 288 // First base-name-conflict resolving, use 1 as initial ordinal number. |
277 file_name_count_map_[base_file_name] = 1; | 289 file_name_count_map_[base_file_name] = 1; |
278 ordinal_number = 1; | 290 ordinal_number = 1; |
279 } else { | 291 } else { |
280 // We have met same base-name conflict, use latest ordinal number. | 292 // We have met same base-name conflict, use latest ordinal number. |
281 ordinal_number = it->second; | 293 ordinal_number = it->second; |
282 } | 294 } |
283 | 295 |
284 if (ordinal_number > (kMaxFileOrdinalNumber - 1)) { | 296 if (ordinal_number > (kMaxFileOrdinalNumber - 1)) { |
285 // Use a random file from temporary file. | 297 // Use a random file from temporary file. |
286 file_util::CreateTemporaryFileName(&file_name); | 298 FilePath temp_file; |
287 file_name = file_util::GetFilenameFromPath(file_name); | 299 file_util::CreateTemporaryFileName(&temp_file); |
| 300 file_name = temp_file.RemoveExtension().BaseName().value(); |
288 // Get safe pure file name. | 301 // Get safe pure file name. |
289 if (!GetSafePureFileName(saved_main_directory_path_, std::wstring(), | 302 if (!GetSafePureFileName(saved_main_directory_path_, |
| 303 FilePath::StringType(), |
290 kMaxFilePathLength, &file_name)) | 304 kMaxFilePathLength, &file_name)) |
291 return false; | 305 return false; |
292 } else { | 306 } else { |
293 uint32 i; | 307 uint32 i; |
294 for (i = ordinal_number; i < kMaxFileOrdinalNumber; ++i) { | 308 for (i = ordinal_number; i < kMaxFileOrdinalNumber; ++i) { |
295 std::wstring new_name = | 309 FilePath::StringType new_name = base_file_name + |
296 StringPrintf(L"%ls(%d)", base_file_name.c_str(), i) + file_name_ext; | 310 StringPrintf(FILE_PATH_LITERAL("(%d)"), i) + file_name_ext; |
297 if (file_name_set_.find(new_name) == file_name_set_.end()) { | 311 if (file_name_set_.find(new_name) == file_name_set_.end()) { |
298 // Resolved name conflict. | 312 // Resolved name conflict. |
299 file_name = new_name; | 313 file_name = new_name; |
300 file_name_count_map_[base_file_name] = ++i; | 314 file_name_count_map_[base_file_name] = ++i; |
301 break; | 315 break; |
302 } | 316 } |
303 } | 317 } |
304 } | 318 } |
305 | 319 |
306 file_name_set_.insert(file_name); | 320 file_name_set_.insert(file_name); |
(...skipping 20 matching lines...) Expand all Loading... |
327 | 341 |
328 DCHECK(!saved_main_file_path_.empty()); | 342 DCHECK(!saved_main_file_path_.empty()); |
329 | 343 |
330 save_item->SetSaveId(info->save_id); | 344 save_item->SetSaveId(info->save_id); |
331 save_item->SetTotalBytes(info->total_bytes); | 345 save_item->SetTotalBytes(info->total_bytes); |
332 | 346 |
333 // Determine the proper path for a saving job, by choosing either the default | 347 // Determine the proper path for a saving job, by choosing either the default |
334 // save directory, or prompting the user. | 348 // save directory, or prompting the user. |
335 DCHECK(!save_item->has_final_name()); | 349 DCHECK(!save_item->has_final_name()); |
336 if (info->url != page_url_) { | 350 if (info->url != page_url_) { |
337 std::wstring generated_name; | 351 FilePath::StringType generated_name; |
338 // For HTML resource file, make sure it will have .htm as extension name, | 352 // For HTML resource file, make sure it will have .htm as extension name, |
339 // otherwise, when you open the saved page in Chrome again, download | 353 // otherwise, when you open the saved page in Chrome again, download |
340 // file manager will treat it as downloadable resource, and download it | 354 // file manager will treat it as downloadable resource, and download it |
341 // instead of opening it as HTML. | 355 // instead of opening it as HTML. |
342 bool need_html_ext = | 356 bool need_html_ext = |
343 info->save_source == SaveFileCreateInfo::SAVE_FILE_FROM_DOM; | 357 info->save_source == SaveFileCreateInfo::SAVE_FILE_FROM_DOM; |
344 if (!GenerateFilename(info->content_disposition, | 358 if (!GenerateFilename(info->content_disposition, |
345 info->url, | 359 GURL(info->url), |
346 need_html_ext, | 360 need_html_ext, |
347 &generated_name)) { | 361 &generated_name)) { |
348 // We can not generate file name for this SaveItem, so we cancel the | 362 // We can not generate file name for this SaveItem, so we cancel the |
349 // saving page job if the save source is from serialized DOM data. | 363 // saving page job if the save source is from serialized DOM data. |
350 // Otherwise, it means this SaveItem is sub-resource type, we treat it | 364 // Otherwise, it means this SaveItem is sub-resource type, we treat it |
351 // as an error happened on saving. We can ignore this type error for | 365 // as an error happened on saving. We can ignore this type error for |
352 // sub-resource links which will be resolved as absolute links instead | 366 // sub-resource links which will be resolved as absolute links instead |
353 // of local links in final saved contents. | 367 // of local links in final saved contents. |
354 if (info->save_source == SaveFileCreateInfo::SAVE_FILE_FROM_DOM) | 368 if (info->save_source == SaveFileCreateInfo::SAVE_FILE_FROM_DOM) |
355 Cancel(true); | 369 Cancel(true); |
356 else | 370 else |
357 SaveFinished(save_item->save_id(), 0, false); | 371 SaveFinished(save_item->save_id(), 0, false); |
358 return; | 372 return; |
359 } | 373 } |
360 | 374 |
361 // When saving page as only-HTML, we only have a SaveItem whose url | 375 // When saving page as only-HTML, we only have a SaveItem whose url |
362 // must be page_url_. | 376 // must be page_url_. |
363 DCHECK(save_type_ == SAVE_AS_COMPLETE_HTML); | 377 DCHECK(save_type_ == SAVE_AS_COMPLETE_HTML); |
364 DCHECK(!saved_main_directory_path_.empty()); | 378 DCHECK(!saved_main_directory_path_.empty()); |
365 | 379 |
366 // Now we get final name retrieved from GenerateFilename, we will use it | 380 // Now we get final name retrieved from GenerateFilename, we will use it |
367 // rename the SaveItem. | 381 // rename the SaveItem. |
368 std::wstring final_name = saved_main_directory_path_; | 382 FilePath final_name = saved_main_directory_path_.Append(generated_name); |
369 file_util::AppendToPath(&final_name, generated_name); | 383 save_item->Rename(final_name.ToWStringHack()); |
370 save_item->Rename(final_name); | |
371 } else { | 384 } else { |
372 // It is the main HTML file, use the name chosen by the user. | 385 // It is the main HTML file, use the name chosen by the user. |
373 save_item->Rename(saved_main_file_path_); | 386 save_item->Rename(saved_main_file_path_.ToWStringHack()); |
374 } | 387 } |
375 | 388 |
376 // If the save source is from file system, inform SaveFileManager to copy | 389 // If the save source is from file system, inform SaveFileManager to copy |
377 // corresponding file to the file path which this SaveItem specifies. | 390 // corresponding file to the file path which this SaveItem specifies. |
378 if (info->save_source == SaveFileCreateInfo::SAVE_FILE_FROM_FILE) { | 391 if (info->save_source == SaveFileCreateInfo::SAVE_FILE_FROM_FILE) { |
379 file_manager_->GetSaveLoop()->PostTask(FROM_HERE, | 392 file_manager_->GetSaveLoop()->PostTask(FROM_HERE, |
380 NewRunnableMethod(file_manager_, | 393 NewRunnableMethod(file_manager_, |
381 &SaveFileManager::SaveLocalFile, | 394 &SaveFileManager::SaveLocalFile, |
382 save_item->url(), | 395 save_item->url(), |
383 save_item->save_id(), | 396 save_item->save_id(), |
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
487 | 500 |
488 // Inform the DownloadItem we have canceled whole save page job. | 501 // Inform the DownloadItem we have canceled whole save page job. |
489 DCHECK(download_); | 502 DCHECK(download_); |
490 download_->Cancel(false); | 503 download_->Cancel(false); |
491 } | 504 } |
492 | 505 |
493 void SavePackage::CheckFinish() { | 506 void SavePackage::CheckFinish() { |
494 if (in_process_count() || finished_) | 507 if (in_process_count() || finished_) |
495 return; | 508 return; |
496 | 509 |
497 std::wstring dir = save_type_ == SAVE_AS_COMPLETE_HTML ? | 510 FilePath dir = save_type_ == SAVE_AS_COMPLETE_HTML ? |
498 saved_main_directory_path_ : | 511 saved_main_directory_path_ : |
499 L""; | 512 FilePath(); |
500 | 513 |
501 // This vector contains the final names of all the successfully saved files | 514 // This vector contains the final names of all the successfully saved files |
502 // along with their save ids. It will be passed to SaveFileManager to do the | 515 // along with their save ids. It will be passed to SaveFileManager to do the |
503 // renaming job. | 516 // renaming job. |
504 FinalNameList final_names; | 517 FinalNameList final_names; |
505 for (SavedItemMap::iterator it = saved_success_items_.begin(); | 518 for (SavedItemMap::iterator it = saved_success_items_.begin(); |
506 it != saved_success_items_.end(); ++it) | 519 it != saved_success_items_.end(); ++it) |
507 final_names.push_back(std::make_pair(it->first, | 520 final_names.push_back(std::make_pair(it->first, |
508 it->second->full_path())); | 521 it->second->full_path())); |
509 | 522 |
510 file_manager_->GetSaveLoop()->PostTask(FROM_HERE, | 523 file_manager_->GetSaveLoop()->PostTask(FROM_HERE, |
511 NewRunnableMethod(file_manager_, | 524 NewRunnableMethod(file_manager_, |
512 &SaveFileManager::RenameAllFiles, | 525 &SaveFileManager::RenameAllFiles, |
513 final_names, | 526 final_names, |
514 dir, | 527 dir.ToWStringHack(), |
515 web_contents_->process()->host_id(), | 528 web_contents_->process()->host_id(), |
516 web_contents_->render_view_host()->routing_id())); | 529 web_contents_->render_view_host()->routing_id())); |
517 } | 530 } |
518 | 531 |
519 // Successfully finished all items of this SavePackage. | 532 // Successfully finished all items of this SavePackage. |
520 void SavePackage::Finish() { | 533 void SavePackage::Finish() { |
521 // User may cancel the job when we're moving files to the final directory. | 534 // User may cancel the job when we're moving files to the final directory. |
522 if (canceled()) | 535 if (canceled()) |
523 return; | 536 return; |
524 | 537 |
(...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
664 | 677 |
665 | 678 |
666 // Open download page in windows explorer on file thread, to avoid blocking the | 679 // Open download page in windows explorer on file thread, to avoid blocking the |
667 // user interface. | 680 // user interface. |
668 void SavePackage::ShowDownloadInShell() { | 681 void SavePackage::ShowDownloadInShell() { |
669 DCHECK(file_manager_); | 682 DCHECK(file_manager_); |
670 DCHECK(finished_ && !canceled() && !saved_main_file_path_.empty()); | 683 DCHECK(finished_ && !canceled() && !saved_main_file_path_.empty()); |
671 file_manager_->GetSaveLoop()->PostTask(FROM_HERE, | 684 file_manager_->GetSaveLoop()->PostTask(FROM_HERE, |
672 NewRunnableMethod(file_manager_, | 685 NewRunnableMethod(file_manager_, |
673 &SaveFileManager::OnShowSavedFileInShell, | 686 &SaveFileManager::OnShowSavedFileInShell, |
674 saved_main_file_path_)); | 687 saved_main_file_path_.ToWStringHack())); |
675 } | 688 } |
676 | 689 |
677 // Calculate the percentage of whole save page job. | 690 // Calculate the percentage of whole save page job. |
678 int SavePackage::PercentComplete() { | 691 int SavePackage::PercentComplete() { |
679 if (!all_save_items_count_) | 692 if (!all_save_items_count_) |
680 return 0; | 693 return 0; |
681 else if (!in_process_count()) | 694 else if (!in_process_count()) |
682 return 100; | 695 return 100; |
683 else | 696 else |
684 return completed_count() / all_save_items_count_; | 697 return completed_count() / all_save_items_count_; |
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
756 | 769 |
757 // Collect all saved success items. | 770 // Collect all saved success items. |
758 for (SavedItemMap::iterator it = saved_success_items_.begin(); | 771 for (SavedItemMap::iterator it = saved_success_items_.begin(); |
759 it != saved_success_items_.end(); ++it) { | 772 it != saved_success_items_.end(); ++it) { |
760 DCHECK(it->second->has_final_name()); | 773 DCHECK(it->second->has_final_name()); |
761 saved_links.push_back(it->second->url()); | 774 saved_links.push_back(it->second->url()); |
762 saved_file_paths.push_back(it->second->file_name()); | 775 saved_file_paths.push_back(it->second->file_name()); |
763 } | 776 } |
764 | 777 |
765 // Get the relative directory name. | 778 // Get the relative directory name. |
766 std::wstring::size_type last_slash = saved_main_directory_path_.rfind(L'\\'); | 779 FilePath relative_dir_name = saved_main_directory_path_.BaseName(); |
767 DCHECK(last_slash != std::wstring::npos); | |
768 std::wstring relative_dir_name = std::wstring(saved_main_directory_path_, | |
769 last_slash + 1); | |
770 | 780 |
771 relative_dir_name = std::wstring(L"./") + relative_dir_name + L"/"; | 781 std::wstring relative_dir_name_str = std::wstring(L"./") + |
| 782 relative_dir_name.ToWStringHack() + L"/"; |
772 | 783 |
773 web_contents_->render_view_host()-> | 784 web_contents_->render_view_host()-> |
774 GetSerializedHtmlDataForCurrentPageWithLocalLinks( | 785 GetSerializedHtmlDataForCurrentPageWithLocalLinks( |
775 saved_links, saved_file_paths, relative_dir_name); | 786 saved_links, saved_file_paths, relative_dir_name_str); |
776 } | 787 } |
777 | 788 |
778 // Process the serialized HTML content data of a specified web page | 789 // Process the serialized HTML content data of a specified web page |
779 // retrieved from render process. | 790 // retrieved from render process. |
780 void SavePackage::OnReceivedSerializedHtmlData(const GURL& frame_url, | 791 void SavePackage::OnReceivedSerializedHtmlData(const GURL& frame_url, |
781 const std::string& data, | 792 const std::string& data, |
782 int32 status) { | 793 int32 status) { |
783 webkit_glue::DomSerializerDelegate::PageSavingSerializationStatus flag = | 794 webkit_glue::DomSerializerDelegate::PageSavingSerializationStatus flag = |
784 static_cast<webkit_glue::DomSerializerDelegate::PageSavingSerializationSta
tus> | 795 static_cast<webkit_glue::DomSerializerDelegate::PageSavingSerializationSta
tus> |
785 (status); | 796 (status); |
(...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
892 } else { | 903 } else { |
893 // No resource files need to be saved, treat it as user cancel. | 904 // No resource files need to be saved, treat it as user cancel. |
894 Cancel(true); | 905 Cancel(true); |
895 } | 906 } |
896 } | 907 } |
897 | 908 |
898 void SavePackage::SetShouldPromptUser(bool should_prompt) { | 909 void SavePackage::SetShouldPromptUser(bool should_prompt) { |
899 g_should_prompt_for_filename = should_prompt; | 910 g_should_prompt_for_filename = should_prompt; |
900 } | 911 } |
901 | 912 |
902 std::wstring SavePackage::GetSuggestNameForSaveAs(PrefService* prefs, | 913 // static |
903 const std::wstring& name) { | 914 FilePath SavePackage::GetSuggestNameForSaveAs(PrefService* prefs, |
| 915 const FilePath& name) { |
904 // Check whether the preference has the preferred directory for saving file. | 916 // Check whether the preference has the preferred directory for saving file. |
905 // If not, initialize it with default directory. | 917 // If not, initialize it with default directory. |
906 if (!prefs->IsPrefRegistered(prefs::kSaveFileDefaultDirectory)) { | 918 if (!prefs->IsPrefRegistered(prefs::kSaveFileDefaultDirectory)) { |
907 std::wstring default_save_path; | 919 FilePath default_save_path; |
908 if (!PathService::Get(chrome::DIR_DEFAULT_DOWNLOADS, | 920 if (!PathService::Get(chrome::DIR_DEFAULT_DOWNLOADS, |
909 &default_save_path)) | 921 &default_save_path)) |
910 NOTREACHED(); | 922 NOTREACHED(); |
911 prefs->RegisterStringPref(prefs::kSaveFileDefaultDirectory, | 923 prefs->RegisterStringPref(prefs::kSaveFileDefaultDirectory, |
912 default_save_path); | 924 default_save_path.ToWStringHack()); |
913 } | 925 } |
914 | 926 |
915 // Get the directory from preference. | 927 // Get the directory from preference. |
916 StringPrefMember save_file_path; | 928 StringPrefMember save_file_path; |
917 save_file_path.Init(prefs::kSaveFileDefaultDirectory, prefs, NULL); | 929 save_file_path.Init(prefs::kSaveFileDefaultDirectory, prefs, NULL); |
918 DCHECK(!(*save_file_path).empty()); | 930 DCHECK(!(*save_file_path).empty()); |
919 | 931 |
920 // Ask user for getting final saving name. | 932 // Ask user for getting final saving name. |
921 std::wstring suggest_name, file_name; | 933 std::wstring file_name = name.ToWStringHack(); |
922 | |
923 file_name = name; | |
924 file_util::ReplaceIllegalCharacters(&file_name, L' '); | 934 file_util::ReplaceIllegalCharacters(&file_name, L' '); |
925 suggest_name = *save_file_path; | 935 FilePath suggest_name = FilePath::FromWStringHack(save_file_path.GetValue()); |
926 file_util::AppendToPath(&suggest_name, file_name); | 936 suggest_name = suggest_name.Append(file_name); |
927 | 937 |
928 return suggest_name; | 938 return suggest_name; |
929 } | 939 } |
930 | 940 |
931 // Static. | 941 // Static. |
932 bool SavePackage::GetSaveInfo(const std::wstring& suggest_name, | 942 bool SavePackage::GetSaveInfo(const FilePath& suggest_name, |
933 HWND container_hwnd, | 943 HWND container_hwnd, |
934 SavePackageParam* param, | 944 SavePackageParam* param, |
935 DownloadManager* download_manager) { | 945 DownloadManager* download_manager) { |
936 // TODO(tc): It might be nice to move this code into the download | 946 // TODO(tc): It might be nice to move this code into the download |
937 // manager. http://crbug.com/6025 | 947 // manager. http://crbug.com/6025 |
938 | 948 |
939 // Use "Web Page, Complete" option as default choice of saving page. | 949 // Use "Web Page, Complete" option as default choice of saving page. |
940 unsigned index = 2; | 950 unsigned index = 2; |
941 | 951 |
942 // If the contents can not be saved as complete-HTML, do not show the | 952 // If the contents can not be saved as complete-HTML, do not show the |
943 // file filters. | 953 // file filters. |
944 if (CanSaveAsComplete(param->current_tab_mime_type)) { | 954 if (CanSaveAsComplete(param->current_tab_mime_type)) { |
945 // Create filter string. | 955 // Create filter string. |
946 std::wstring filter = l10n_util::GetString(IDS_SAVE_PAGE_FILTER); | 956 std::wstring filter = l10n_util::GetString(IDS_SAVE_PAGE_FILTER); |
947 filter.resize(filter.size() + 2); | 957 filter.resize(filter.size() + 2); |
948 filter[filter.size() - 1] = L'\0'; | 958 filter[filter.size() - 1] = L'\0'; |
949 filter[filter.size() - 2] = L'\0'; | 959 filter[filter.size() - 2] = L'\0'; |
950 | 960 |
951 if (g_should_prompt_for_filename) { | 961 if (g_should_prompt_for_filename) { |
952 // Since we take the suggested name from the web page's title, we want to | 962 // Since we take the suggested name from the web page's title, we want to |
953 // ignore the file extension generated by SaveFileAsWithFilter, since it | 963 // ignore the file extension generated by SaveFileAsWithFilter, since it |
954 // will always be ".htm". | 964 // will always be ".htm". |
| 965 // TODO(estade): is this saved_main_file_path assignment behavior desired? |
| 966 // It was copied from previous code but seems strange. |
| 967 std::wstring main_file_path; |
955 if (!win_util::SaveFileAsWithFilter(container_hwnd, | 968 if (!win_util::SaveFileAsWithFilter(container_hwnd, |
956 suggest_name, | 969 suggest_name.value(), |
957 filter, | 970 filter, |
958 L"htm", | 971 L"htm", |
959 true, | 972 true, |
960 &index, | 973 &index, |
961 ¶m->saved_main_file_path)) | 974 &main_file_path)) { |
| 975 param->saved_main_file_path = FilePath(main_file_path); |
962 return false; | 976 return false; |
| 977 } |
963 } else { | 978 } else { |
964 param->saved_main_file_path = suggest_name; | 979 param->saved_main_file_path = suggest_name; |
965 } | 980 } |
966 } else { | 981 } else { |
967 if (g_should_prompt_for_filename) { | 982 if (g_should_prompt_for_filename) { |
968 if (!win_util::SaveFileAs(container_hwnd, suggest_name, | 983 // TODO(estade): see above comment. |
969 ¶m->saved_main_file_path)) | 984 std::wstring main_file_path; |
| 985 if (!win_util::SaveFileAs(container_hwnd, suggest_name.value(), |
| 986 &main_file_path)) |
| 987 param->saved_main_file_path = FilePath(main_file_path); |
970 return false; | 988 return false; |
971 } else { | 989 } else { |
972 param->saved_main_file_path = suggest_name; | 990 param->saved_main_file_path = suggest_name; |
973 } | 991 } |
974 // Set save-as type to only-HTML if the contents of current tab can not be | 992 // Set save-as type to only-HTML if the contents of current tab can not be |
975 // saved as complete-HTML. | 993 // saved as complete-HTML. |
976 index = 1; | 994 index = 1; |
977 } | 995 } |
978 | 996 |
979 DCHECK(download_manager); | 997 DCHECK(download_manager); |
980 // Ensure the filename is safe. | 998 // Ensure the filename is safe. |
981 FilePath path(param->saved_main_file_path); | 999 download_manager->GenerateSafeFilename(param->current_tab_mime_type, |
982 download_manager->GenerateSafeFilename(param->current_tab_mime_type, &path); | 1000 ¶m->saved_main_file_path); |
983 param->saved_main_file_path = path.ToWStringHack(); | |
984 | 1001 |
985 // The option index is not zero-based. | 1002 // The option index is not zero-based. |
986 DCHECK(index > 0 && index < 3); | 1003 DCHECK(index > 0 && index < 3); |
987 param->dir = file_util::GetDirectoryFromPath(param->saved_main_file_path); | 1004 param->dir = param->saved_main_file_path.DirName(); |
988 | 1005 |
989 StringPrefMember save_file_path; | 1006 StringPrefMember save_file_path; |
990 save_file_path.Init(prefs::kSaveFileDefaultDirectory, param->prefs, NULL); | 1007 save_file_path.Init(prefs::kSaveFileDefaultDirectory, param->prefs, NULL); |
991 // If user change the default saving directory, we will remember it just | 1008 // If user change the default saving directory, we will remember it just |
992 // like IE and FireFox. | 1009 // like IE and FireFox. |
993 if (save_file_path.GetValue() != param->dir) | 1010 if (save_file_path.GetValue() != param->dir.ToWStringHack()) |
994 save_file_path.SetValue(param->dir); | 1011 save_file_path.SetValue(param->dir.ToWStringHack()); |
995 | 1012 |
996 param->save_type = (index == 1) ? SavePackage::SAVE_AS_ONLY_HTML : | 1013 param->save_type = (index == 1) ? SavePackage::SAVE_AS_ONLY_HTML : |
997 SavePackage::SAVE_AS_COMPLETE_HTML; | 1014 SavePackage::SAVE_AS_COMPLETE_HTML; |
998 | 1015 |
999 if (param->save_type == SavePackage::SAVE_AS_COMPLETE_HTML) { | 1016 if (param->save_type == SavePackage::SAVE_AS_COMPLETE_HTML) { |
1000 // Make new directory for saving complete file. | 1017 // Make new directory for saving complete file. |
1001 std::wstring file_name = | 1018 param->dir = param->dir.Append( |
1002 file_util::GetFilenameFromPath(param->saved_main_file_path); | 1019 param->saved_main_file_path.RemoveExtension().BaseName().value() + |
1003 std::wstring::size_type last_dot = file_name.rfind(L'.'); | 1020 FILE_PATH_LITERAL("_files")); |
1004 std::wstring pure_file_name; | |
1005 if (last_dot == std::wstring::npos) | |
1006 pure_file_name = file_name; | |
1007 else | |
1008 pure_file_name = std::wstring(file_name, 0, last_dot); | |
1009 pure_file_name += L"_files"; | |
1010 file_util::AppendToPath(¶m->dir, pure_file_name); | |
1011 } | 1021 } |
1012 | 1022 |
1013 return true; | 1023 return true; |
1014 } | 1024 } |
1015 | 1025 |
1016 // Static. | |
1017 bool SavePackage::GetBaseFileNameAndFileOrdinalNumber( | |
1018 const std::wstring& file_name, | |
1019 std::wstring* base_file_name, | |
1020 std::wstring* file_ordinal_number) { | |
1021 if (file_name.empty() || !base_file_name || !file_ordinal_number) | |
1022 return false; | |
1023 | |
1024 // Find dot position. | |
1025 std::wstring::size_type dot_position = file_name.rfind(L"."); | |
1026 // Find position of right parenthesis. | |
1027 std::wstring::size_type parenthesis_right; | |
1028 if (std::wstring::npos == dot_position) | |
1029 parenthesis_right = file_name.rfind(L')'); | |
1030 else | |
1031 parenthesis_right = dot_position - 1; | |
1032 // The latest character of pure file name is not ")", return false. | |
1033 if (std::wstring::npos == parenthesis_right) | |
1034 return false; | |
1035 if (file_name.at(parenthesis_right) != L')') | |
1036 return false; | |
1037 // Find position of left parenthesis. | |
1038 std::wstring::size_type parenthesis_left = file_name.rfind(L'('); | |
1039 if (std::wstring::npos == parenthesis_left) | |
1040 return false; | |
1041 | |
1042 if (parenthesis_right <= parenthesis_left) | |
1043 return false; | |
1044 // Check whether content between left parenthesis and right parenthesis is | |
1045 // numeric or not. | |
1046 std::wstring ordinal_number(file_name, parenthesis_left + 1, | |
1047 parenthesis_right - parenthesis_left - 1); | |
1048 for (std::wstring::const_iterator cit = ordinal_number.begin(); | |
1049 cit != ordinal_number.end(); ++cit) | |
1050 if (!IsAsciiDigit(*cit)) | |
1051 return false; | |
1052 | |
1053 *base_file_name = std::wstring(file_name, 0, parenthesis_left); | |
1054 *file_ordinal_number = ordinal_number; | |
1055 return true; | |
1056 } | |
1057 | |
1058 // Static | 1026 // Static |
1059 bool SavePackage::IsSavableURL(const GURL& url) { | 1027 bool SavePackage::IsSavableURL(const GURL& url) { |
1060 return url.SchemeIs("http") || url.SchemeIs("https") || | 1028 return url.SchemeIs("http") || url.SchemeIs("https") || |
1061 url.SchemeIs("file") || url.SchemeIs("ftp"); | 1029 url.SchemeIs("file") || url.SchemeIs("ftp"); |
1062 } | 1030 } |
1063 | 1031 |
1064 // Static | 1032 // Static |
1065 bool SavePackage::IsSavableContents(const std::string& contents_mime_type) { | 1033 bool SavePackage::IsSavableContents(const std::string& contents_mime_type) { |
1066 // WebKit creates Document object when MIME type is application/xhtml+xml, | 1034 // WebKit creates Document object when MIME type is application/xhtml+xml, |
1067 // so we also support this MIME type. | 1035 // so we also support this MIME type. |
1068 return contents_mime_type == "text/html" || | 1036 return contents_mime_type == "text/html" || |
1069 contents_mime_type == "text/xml" || | 1037 contents_mime_type == "text/xml" || |
1070 contents_mime_type == "application/xhtml+xml" || | 1038 contents_mime_type == "application/xhtml+xml" || |
1071 contents_mime_type == "text/plain" || | 1039 contents_mime_type == "text/plain" || |
1072 contents_mime_type == "text/css" || | 1040 contents_mime_type == "text/css" || |
1073 net::IsSupportedJavascriptMimeType(contents_mime_type.c_str()); | 1041 net::IsSupportedJavascriptMimeType(contents_mime_type.c_str()); |
1074 } | 1042 } |
1075 | 1043 |
1076 // Static | 1044 // Static |
1077 bool SavePackage::CanSaveAsComplete(const std::string& contents_mime_type) { | 1045 bool SavePackage::CanSaveAsComplete(const std::string& contents_mime_type) { |
1078 return contents_mime_type == "text/html"; | 1046 return contents_mime_type == "text/html"; |
1079 } | 1047 } |
1080 | 1048 |
1081 // Static | 1049 // Static |
1082 bool SavePackage::GetSafePureFileName(const std::wstring& dir_path, | 1050 bool SavePackage::GetSafePureFileName(const FilePath& dir_path, |
1083 const std::wstring& file_name_ext, | 1051 const FilePath::StringType& file_name_ext, |
1084 uint32 max_file_path_len, | 1052 uint32 max_file_path_len, |
1085 std::wstring* pure_file_name) { | 1053 FilePath::StringType* pure_file_name) { |
1086 DCHECK(!pure_file_name->empty()); | 1054 DCHECK(!pure_file_name->empty()); |
1087 std::wstring final_name = dir_path; | 1055 int available_length = static_cast<int>( |
1088 file_util::AppendToPath(&final_name, *pure_file_name); | 1056 max_file_path_len - dir_path.value().length() - file_name_ext.length()); |
1089 // Get total length of dir path, including ending "\". | 1057 // Need an extra space for the separator. |
1090 const std::wstring::size_type dir_path_length = | 1058 if (!file_util::EndsWithSeparator(dir_path)) |
1091 final_name.length() - pure_file_name->length(); | 1059 --available_length; |
1092 // Get available length for putting dir path and pure file name. | |
1093 const std::wstring::size_type available_length = | |
1094 static_cast<std::wstring::size_type>(max_file_path_len) - | |
1095 file_name_ext.length(); | |
1096 | 1060 |
1097 if (final_name.length() <= available_length) | 1061 // Plenty of room. |
| 1062 if (static_cast<int>(pure_file_name->length()) <= available_length) |
1098 return true; | 1063 return true; |
1099 | 1064 |
1100 if (available_length > dir_path_length) { | 1065 // Limited room. Truncate |pure_file_name| to fit. |
| 1066 if (available_length > 0) { |
1101 *pure_file_name = | 1067 *pure_file_name = |
1102 pure_file_name->substr(0, available_length - dir_path_length); | 1068 pure_file_name->substr(0, available_length); |
1103 return true; | 1069 return true; |
1104 } else { | |
1105 pure_file_name->clear(); | |
1106 return false; | |
1107 } | 1070 } |
| 1071 |
| 1072 // Not enough room to even use a shortened |pure_file_name|. |
| 1073 pure_file_name->clear(); |
| 1074 return false; |
1108 } | 1075 } |
| 1076 |
OLD | NEW |