| OLD | NEW |
| 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2013 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/media_galleries/win/mtp_device_operations_util.h" | 5 #include "chrome/browser/media_galleries/win/mtp_device_operations_util.h" |
| 6 | 6 |
| 7 #include <portabledevice.h> | 7 #include <portabledevice.h> |
| 8 | 8 |
| 9 #include <algorithm> | 9 #include <algorithm> |
| 10 | 10 |
| (...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 111 HRESULT hr = properties_values->GetStringValue(WPD_OBJECT_ORIGINAL_FILE_NAME, | 111 HRESULT hr = properties_values->GetStringValue(WPD_OBJECT_ORIGINAL_FILE_NAME, |
| 112 &buffer); | 112 &buffer); |
| 113 if (FAILED(hr)) | 113 if (FAILED(hr)) |
| 114 hr = properties_values->GetStringValue(WPD_OBJECT_NAME, &buffer); | 114 hr = properties_values->GetStringValue(WPD_OBJECT_NAME, &buffer); |
| 115 if (SUCCEEDED(hr)) | 115 if (SUCCEEDED(hr)) |
| 116 result.assign(buffer); | 116 result.assign(buffer); |
| 117 return result; | 117 return result; |
| 118 } | 118 } |
| 119 | 119 |
| 120 // Gets the last modified time of the object from the property key values | 120 // Gets the last modified time of the object from the property key values |
| 121 // specified by the |properties_values|. On success, returns true and fills in | 121 // specified by the |properties_values|. On success, fills in |
| 122 // |last_modified_time|. | 122 // |last_modified_time|. |
| 123 bool GetLastModifiedTime(IPortableDeviceValues* properties_values, | 123 void GetLastModifiedTime(IPortableDeviceValues* properties_values, |
| 124 base::Time* last_modified_time) { | 124 base::Time* last_modified_time) { |
| 125 DCHECK(properties_values); | 125 DCHECK(properties_values); |
| 126 DCHECK(last_modified_time); | 126 DCHECK(last_modified_time); |
| 127 base::win::ScopedPropVariant last_modified_date; | 127 base::win::ScopedPropVariant last_modified_date; |
| 128 HRESULT hr = properties_values->GetValue(WPD_OBJECT_DATE_MODIFIED, | 128 HRESULT hr = properties_values->GetValue(WPD_OBJECT_DATE_MODIFIED, |
| 129 last_modified_date.Receive()); | 129 last_modified_date.Receive()); |
| 130 if (FAILED(hr)) | 130 if (FAILED(hr)) |
| 131 return false; | 131 return; |
| 132 | 132 |
| 133 bool last_modified_time_set = (last_modified_date.get().vt == VT_DATE); | 133 // Some PTP devices don't provide an mtime. Try using the ctime instead. |
| 134 if (last_modified_time_set) { | 134 if (last_modified_date.get().vt != VT_DATE) { |
| 135 SYSTEMTIME system_time; | 135 last_modified_date.Reset(); |
| 136 FILETIME file_time; | 136 HRESULT hr = properties_values->GetValue(WPD_OBJECT_DATE_CREATED, |
| 137 if (VariantTimeToSystemTime(last_modified_date.get().date, &system_time) && | 137 last_modified_date.Receive()); |
| 138 SystemTimeToFileTime(&system_time, &file_time)) { | 138 if (FAILED(hr)) |
| 139 *last_modified_time = base::Time::FromFileTime(file_time); | 139 return; |
| 140 } else { | |
| 141 last_modified_time_set = false; | |
| 142 } | |
| 143 } | 140 } |
| 144 return last_modified_time_set; | 141 |
| 142 SYSTEMTIME system_time; |
| 143 FILETIME file_time; |
| 144 if (last_modified_date.get().vt == VT_DATE && |
| 145 VariantTimeToSystemTime(last_modified_date.get().date, &system_time) && |
| 146 SystemTimeToFileTime(&system_time, &file_time)) { |
| 147 *last_modified_time = base::Time::FromFileTime(file_time); |
| 148 } |
| 145 } | 149 } |
| 146 | 150 |
| 147 // Gets the size of the file object in bytes from the property key values | 151 // Gets the size of the file object in bytes from the property key values |
| 148 // specified by the |properties_values|. On success, returns true and fills | 152 // specified by the |properties_values|. On success, returns true and fills |
| 149 // in |size|. | 153 // in |size|. |
| 150 bool GetObjectSize(IPortableDeviceValues* properties_values, int64* size) { | 154 bool GetObjectSize(IPortableDeviceValues* properties_values, int64* size) { |
| 151 DCHECK(properties_values); | 155 DCHECK(properties_values); |
| 152 DCHECK(size); | 156 DCHECK(size); |
| 153 ULONGLONG actual_size; | 157 ULONGLONG actual_size; |
| 154 HRESULT hr = properties_values->GetUnsignedLargeIntegerValue(WPD_OBJECT_SIZE, | 158 HRESULT hr = properties_values->GetUnsignedLargeIntegerValue(WPD_OBJECT_SIZE, |
| 155 &actual_size); | 159 &actual_size); |
| 156 bool success = SUCCEEDED(hr) && (actual_size <= kint64max); | 160 bool success = SUCCEEDED(hr) && (actual_size <= kint64max); |
| 157 if (success) | 161 if (success) |
| 158 *size = static_cast<int64>(actual_size); | 162 *size = static_cast<int64>(actual_size); |
| 159 return success; | 163 return success; |
| 160 } | 164 } |
| 161 | 165 |
| 162 // Gets the details of the object specified by the |object_id| given the media | 166 // Gets the details of the object specified by the |object_id| given the media |
| 163 // transfer protocol |device|. On success, returns true and fills in |name|, | 167 // transfer protocol |device|. On success, returns true and fills in |name|, |
| 164 // |is_directory|, |size| and |last_modified_time|. | 168 // |is_directory|, |size|. |last_modified_time| will be filled in if possible, |
| 169 // but failure to get it doesn't prevent success. |
| 165 bool GetObjectDetails(IPortableDevice* device, | 170 bool GetObjectDetails(IPortableDevice* device, |
| 166 const base::string16 object_id, | 171 const base::string16 object_id, |
| 167 base::string16* name, | 172 base::string16* name, |
| 168 bool* is_directory, | 173 bool* is_directory, |
| 169 int64* size, | 174 int64* size, |
| 170 base::Time* last_modified_time) { | 175 base::Time* last_modified_time) { |
| 171 base::ThreadRestrictions::AssertIOAllowed(); | 176 base::ThreadRestrictions::AssertIOAllowed(); |
| 172 DCHECK(device); | 177 DCHECK(device); |
| 173 DCHECK(!object_id.empty()); | 178 DCHECK(!object_id.empty()); |
| 174 DCHECK(name); | 179 DCHECK(name); |
| (...skipping 15 matching lines...) Expand all Loading... |
| 190 NULL, | 195 NULL, |
| 191 CLSCTX_INPROC_SERVER); | 196 CLSCTX_INPROC_SERVER); |
| 192 if (FAILED(hr)) | 197 if (FAILED(hr)) |
| 193 return false; | 198 return false; |
| 194 | 199 |
| 195 if (FAILED(properties_to_read->Add(WPD_OBJECT_CONTENT_TYPE)) || | 200 if (FAILED(properties_to_read->Add(WPD_OBJECT_CONTENT_TYPE)) || |
| 196 FAILED(properties_to_read->Add(WPD_OBJECT_FORMAT)) || | 201 FAILED(properties_to_read->Add(WPD_OBJECT_FORMAT)) || |
| 197 FAILED(properties_to_read->Add(WPD_OBJECT_ORIGINAL_FILE_NAME)) || | 202 FAILED(properties_to_read->Add(WPD_OBJECT_ORIGINAL_FILE_NAME)) || |
| 198 FAILED(properties_to_read->Add(WPD_OBJECT_NAME)) || | 203 FAILED(properties_to_read->Add(WPD_OBJECT_NAME)) || |
| 199 FAILED(properties_to_read->Add(WPD_OBJECT_DATE_MODIFIED)) || | 204 FAILED(properties_to_read->Add(WPD_OBJECT_DATE_MODIFIED)) || |
| 205 FAILED(properties_to_read->Add(WPD_OBJECT_DATE_CREATED)) || |
| 200 FAILED(properties_to_read->Add(WPD_OBJECT_SIZE))) | 206 FAILED(properties_to_read->Add(WPD_OBJECT_SIZE))) |
| 201 return false; | 207 return false; |
| 202 | 208 |
| 203 base::win::ScopedComPtr<IPortableDeviceValues> properties_values; | 209 base::win::ScopedComPtr<IPortableDeviceValues> properties_values; |
| 204 hr = properties->GetValues(object_id.c_str(), | 210 hr = properties->GetValues(object_id.c_str(), |
| 205 properties_to_read.get(), | 211 properties_to_read.get(), |
| 206 properties_values.Receive()); | 212 properties_values.Receive()); |
| 207 if (FAILED(hr)) | 213 if (FAILED(hr)) |
| 208 return false; | 214 return false; |
| 209 | 215 |
| 210 *is_directory = IsDirectory(properties_values.get()); | 216 *is_directory = IsDirectory(properties_values.get()); |
| 211 *name = GetObjectName(properties_values.get()); | 217 *name = GetObjectName(properties_values.get()); |
| 212 if (name->empty()) | 218 if (name->empty()) |
| 213 return false; | 219 return false; |
| 214 | 220 |
| 215 if (*is_directory) { | 221 if (*is_directory) { |
| 216 // Directory entry does not have size and last modified date property key | 222 // Directory entry does not have size and last modified date property key |
| 217 // values. | 223 // values. |
| 218 *size = 0; | 224 *size = 0; |
| 219 *last_modified_time = base::Time(); | 225 *last_modified_time = base::Time(); |
| 220 return true; | 226 return true; |
| 221 } | 227 } |
| 222 return (GetObjectSize(properties_values.get(), size) && | 228 |
| 223 GetLastModifiedTime(properties_values.get(), last_modified_time)); | 229 // Try to get the last modified time, but don't fail if we can't. |
| 230 GetLastModifiedTime(properties_values.get(), last_modified_time); |
| 231 |
| 232 return GetObjectSize(properties_values.get(), size); |
| 224 } | 233 } |
| 225 | 234 |
| 226 // Creates an MTP device object entry for the given |device| and |object_id|. | 235 // Creates an MTP device object entry for the given |device| and |object_id|. |
| 227 // On success, returns true and fills in |entry|. | 236 // On success, returns true and fills in |entry|. |
| 228 bool GetMTPDeviceObjectEntry(IPortableDevice* device, | 237 bool GetMTPDeviceObjectEntry(IPortableDevice* device, |
| 229 const base::string16& object_id, | 238 const base::string16& object_id, |
| 230 MTPDeviceObjectEntry* entry) { | 239 MTPDeviceObjectEntry* entry) { |
| 231 base::ThreadRestrictions::AssertIOAllowed(); | 240 base::ThreadRestrictions::AssertIOAllowed(); |
| 232 DCHECK(device); | 241 DCHECK(device); |
| 233 DCHECK(!object_id.empty()); | 242 DCHECK(!object_id.empty()); |
| (...skipping 165 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 399 object_entries.empty()) | 408 object_entries.empty()) |
| 400 return base::string16(); | 409 return base::string16(); |
| 401 // TODO(thestig): This DCHECK can fail. Multiple MTP objects can have | 410 // TODO(thestig): This DCHECK can fail. Multiple MTP objects can have |
| 402 // the same name. Handle the situation gracefully. Refer to crbug.com/169930 | 411 // the same name. Handle the situation gracefully. Refer to crbug.com/169930 |
| 403 // for more details. | 412 // for more details. |
| 404 DCHECK_EQ(1U, object_entries.size()); | 413 DCHECK_EQ(1U, object_entries.size()); |
| 405 return object_entries[0].object_id; | 414 return object_entries[0].object_id; |
| 406 } | 415 } |
| 407 | 416 |
| 408 } // namespace media_transfer_protocol | 417 } // namespace media_transfer_protocol |
| OLD | NEW |