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 #include <stdint.h> | 8 #include <stdint.h> |
9 | 9 |
10 #include <algorithm> | 10 #include <algorithm> |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
68 // the device objects. On failure, returns NULL. | 68 // the device objects. On failure, returns NULL. |
69 // |parent_id| specifies the parent object identifier. | 69 // |parent_id| specifies the parent object identifier. |
70 base::win::ScopedComPtr<IEnumPortableDeviceObjectIDs> GetDeviceObjectEnumerator( | 70 base::win::ScopedComPtr<IEnumPortableDeviceObjectIDs> GetDeviceObjectEnumerator( |
71 IPortableDevice* device, | 71 IPortableDevice* device, |
72 const base::string16& parent_id) { | 72 const base::string16& parent_id) { |
73 base::ThreadRestrictions::AssertIOAllowed(); | 73 base::ThreadRestrictions::AssertIOAllowed(); |
74 DCHECK(device); | 74 DCHECK(device); |
75 DCHECK(!parent_id.empty()); | 75 DCHECK(!parent_id.empty()); |
76 base::win::ScopedComPtr<IPortableDeviceContent> content = | 76 base::win::ScopedComPtr<IPortableDeviceContent> content = |
77 GetDeviceContent(device); | 77 GetDeviceContent(device); |
78 if (!content.get()) | 78 if (!content.Get()) |
79 return base::win::ScopedComPtr<IEnumPortableDeviceObjectIDs>(); | 79 return base::win::ScopedComPtr<IEnumPortableDeviceObjectIDs>(); |
80 | 80 |
81 base::win::ScopedComPtr<IEnumPortableDeviceObjectIDs> enum_object_ids; | 81 base::win::ScopedComPtr<IEnumPortableDeviceObjectIDs> enum_object_ids; |
82 if (SUCCEEDED(content->EnumObjects(0, parent_id.c_str(), NULL, | 82 if (SUCCEEDED(content->EnumObjects(0, parent_id.c_str(), NULL, |
83 enum_object_ids.Receive()))) | 83 enum_object_ids.Receive()))) |
84 return enum_object_ids; | 84 return enum_object_ids; |
85 return base::win::ScopedComPtr<IEnumPortableDeviceObjectIDs>(); | 85 return base::win::ScopedComPtr<IEnumPortableDeviceObjectIDs>(); |
86 } | 86 } |
87 | 87 |
88 // Returns whether the object is a directory/folder/album. |properties_values| | 88 // Returns whether the object is a directory/folder/album. |properties_values| |
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
175 base::Time* last_modified_time) { | 175 base::Time* last_modified_time) { |
176 base::ThreadRestrictions::AssertIOAllowed(); | 176 base::ThreadRestrictions::AssertIOAllowed(); |
177 DCHECK(device); | 177 DCHECK(device); |
178 DCHECK(!object_id.empty()); | 178 DCHECK(!object_id.empty()); |
179 DCHECK(name); | 179 DCHECK(name); |
180 DCHECK(is_directory); | 180 DCHECK(is_directory); |
181 DCHECK(size); | 181 DCHECK(size); |
182 DCHECK(last_modified_time); | 182 DCHECK(last_modified_time); |
183 base::win::ScopedComPtr<IPortableDeviceContent> content = | 183 base::win::ScopedComPtr<IPortableDeviceContent> content = |
184 GetDeviceContent(device); | 184 GetDeviceContent(device); |
185 if (!content.get()) | 185 if (!content.Get()) |
186 return false; | 186 return false; |
187 | 187 |
188 base::win::ScopedComPtr<IPortableDeviceProperties> properties; | 188 base::win::ScopedComPtr<IPortableDeviceProperties> properties; |
189 HRESULT hr = content->Properties(properties.Receive()); | 189 HRESULT hr = content->Properties(properties.Receive()); |
190 if (FAILED(hr)) | 190 if (FAILED(hr)) |
191 return false; | 191 return false; |
192 | 192 |
193 base::win::ScopedComPtr<IPortableDeviceKeyCollection> properties_to_read; | 193 base::win::ScopedComPtr<IPortableDeviceKeyCollection> properties_to_read; |
194 hr = properties_to_read.CreateInstance(__uuidof(PortableDeviceKeyCollection), | 194 hr = properties_to_read.CreateInstance(__uuidof(PortableDeviceKeyCollection), |
195 NULL, | 195 NULL, |
196 CLSCTX_INPROC_SERVER); | 196 CLSCTX_INPROC_SERVER); |
197 if (FAILED(hr)) | 197 if (FAILED(hr)) |
198 return false; | 198 return false; |
199 | 199 |
200 if (FAILED(properties_to_read->Add(WPD_OBJECT_CONTENT_TYPE)) || | 200 if (FAILED(properties_to_read->Add(WPD_OBJECT_CONTENT_TYPE)) || |
201 FAILED(properties_to_read->Add(WPD_OBJECT_FORMAT)) || | 201 FAILED(properties_to_read->Add(WPD_OBJECT_FORMAT)) || |
202 FAILED(properties_to_read->Add(WPD_OBJECT_ORIGINAL_FILE_NAME)) || | 202 FAILED(properties_to_read->Add(WPD_OBJECT_ORIGINAL_FILE_NAME)) || |
203 FAILED(properties_to_read->Add(WPD_OBJECT_NAME)) || | 203 FAILED(properties_to_read->Add(WPD_OBJECT_NAME)) || |
204 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)) || | 205 FAILED(properties_to_read->Add(WPD_OBJECT_DATE_CREATED)) || |
206 FAILED(properties_to_read->Add(WPD_OBJECT_SIZE))) | 206 FAILED(properties_to_read->Add(WPD_OBJECT_SIZE))) |
207 return false; | 207 return false; |
208 | 208 |
209 base::win::ScopedComPtr<IPortableDeviceValues> properties_values; | 209 base::win::ScopedComPtr<IPortableDeviceValues> properties_values; |
210 hr = properties->GetValues(object_id.c_str(), | 210 hr = properties->GetValues(object_id.c_str(), |
211 properties_to_read.get(), | 211 properties_to_read.Get(), |
212 properties_values.Receive()); | 212 properties_values.Receive()); |
213 if (FAILED(hr)) | 213 if (FAILED(hr)) |
214 return false; | 214 return false; |
215 | 215 |
216 *is_directory = IsDirectory(properties_values.get()); | 216 *is_directory = IsDirectory(properties_values.Get()); |
217 *name = GetObjectName(properties_values.get()); | 217 *name = GetObjectName(properties_values.Get()); |
218 if (name->empty()) | 218 if (name->empty()) |
219 return false; | 219 return false; |
220 | 220 |
221 if (*is_directory) { | 221 if (*is_directory) { |
222 // 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 |
223 // values. | 223 // values. |
224 *size = 0; | 224 *size = 0; |
225 *last_modified_time = base::Time(); | 225 *last_modified_time = base::Time(); |
226 return true; | 226 return true; |
227 } | 227 } |
228 | 228 |
229 // Try to get the last modified time, but don't fail if we can't. | 229 // Try to get the last modified time, but don't fail if we can't. |
230 GetLastModifiedTime(properties_values.get(), last_modified_time); | 230 GetLastModifiedTime(properties_values.Get(), last_modified_time); |
231 | 231 |
232 int64_t object_size = GetObjectSize(properties_values.get()); | 232 int64_t object_size = GetObjectSize(properties_values.Get()); |
233 if (object_size < 0) | 233 if (object_size < 0) |
234 return false; | 234 return false; |
235 *size = object_size; | 235 *size = object_size; |
236 return true; | 236 return true; |
237 } | 237 } |
238 | 238 |
239 // Creates an MTP device object entry for the given |device| and |object_id|. | 239 // Creates an MTP device object entry for the given |device| and |object_id|. |
240 // On success, returns true and fills in |entry|. | 240 // On success, returns true and fills in |entry|. |
241 MTPDeviceObjectEntry GetMTPDeviceObjectEntry(IPortableDevice* device, | 241 MTPDeviceObjectEntry GetMTPDeviceObjectEntry(IPortableDevice* device, |
242 const base::string16& object_id) { | 242 const base::string16& object_id) { |
(...skipping 20 matching lines...) Expand all Loading... |
263 bool GetMTPDeviceObjectEntries(IPortableDevice* device, | 263 bool GetMTPDeviceObjectEntries(IPortableDevice* device, |
264 const base::string16& directory_object_id, | 264 const base::string16& directory_object_id, |
265 const base::string16& object_name, | 265 const base::string16& object_name, |
266 MTPDeviceObjectEntries* object_entries) { | 266 MTPDeviceObjectEntries* object_entries) { |
267 base::ThreadRestrictions::AssertIOAllowed(); | 267 base::ThreadRestrictions::AssertIOAllowed(); |
268 DCHECK(device); | 268 DCHECK(device); |
269 DCHECK(!directory_object_id.empty()); | 269 DCHECK(!directory_object_id.empty()); |
270 DCHECK(object_entries); | 270 DCHECK(object_entries); |
271 base::win::ScopedComPtr<IEnumPortableDeviceObjectIDs> enum_object_ids = | 271 base::win::ScopedComPtr<IEnumPortableDeviceObjectIDs> enum_object_ids = |
272 GetDeviceObjectEnumerator(device, directory_object_id); | 272 GetDeviceObjectEnumerator(device, directory_object_id); |
273 if (!enum_object_ids.get()) | 273 if (!enum_object_ids.Get()) |
274 return false; | 274 return false; |
275 | 275 |
276 // Loop calling Next() while S_OK is being returned. | 276 // Loop calling Next() while S_OK is being returned. |
277 const DWORD num_objects_to_request = 10; | 277 const DWORD num_objects_to_request = 10; |
278 const bool get_all_entries = object_name.empty(); | 278 const bool get_all_entries = object_name.empty(); |
279 for (HRESULT hr = S_OK; hr == S_OK;) { | 279 for (HRESULT hr = S_OK; hr == S_OK;) { |
280 DWORD num_objects_fetched = 0; | 280 DWORD num_objects_fetched = 0; |
281 std::unique_ptr<base::char16* []> object_ids( | 281 std::unique_ptr<base::char16* []> object_ids( |
282 new base::char16*[num_objects_to_request]); | 282 new base::char16*[num_objects_to_request]); |
283 hr = enum_object_ids->Next(num_objects_to_request, | 283 hr = enum_object_ids->Next(num_objects_to_request, |
(...skipping 25 matching lines...) Expand all Loading... |
309 DCHECK(!pnp_device_id.empty()); | 309 DCHECK(!pnp_device_id.empty()); |
310 base::win::ScopedComPtr<IPortableDeviceValues> client_info; | 310 base::win::ScopedComPtr<IPortableDeviceValues> client_info; |
311 if (!GetClientInformation(&client_info)) | 311 if (!GetClientInformation(&client_info)) |
312 return base::win::ScopedComPtr<IPortableDevice>(); | 312 return base::win::ScopedComPtr<IPortableDevice>(); |
313 base::win::ScopedComPtr<IPortableDevice> device; | 313 base::win::ScopedComPtr<IPortableDevice> device; |
314 HRESULT hr = device.CreateInstance(__uuidof(PortableDevice), NULL, | 314 HRESULT hr = device.CreateInstance(__uuidof(PortableDevice), NULL, |
315 CLSCTX_INPROC_SERVER); | 315 CLSCTX_INPROC_SERVER); |
316 if (FAILED(hr)) | 316 if (FAILED(hr)) |
317 return base::win::ScopedComPtr<IPortableDevice>(); | 317 return base::win::ScopedComPtr<IPortableDevice>(); |
318 | 318 |
319 hr = device->Open(pnp_device_id.c_str(), client_info.get()); | 319 hr = device->Open(pnp_device_id.c_str(), client_info.Get()); |
320 if (SUCCEEDED(hr)) | 320 if (SUCCEEDED(hr)) |
321 return device; | 321 return device; |
322 if (hr == E_ACCESSDENIED) | 322 if (hr == E_ACCESSDENIED) |
323 DPLOG(ERROR) << "Access denied to open the device"; | 323 DPLOG(ERROR) << "Access denied to open the device"; |
324 return base::win::ScopedComPtr<IPortableDevice>(); | 324 return base::win::ScopedComPtr<IPortableDevice>(); |
325 } | 325 } |
326 | 326 |
327 base::File::Error GetFileEntryInfo( | 327 base::File::Error GetFileEntryInfo( |
328 IPortableDevice* device, | 328 IPortableDevice* device, |
329 const base::string16& object_id, | 329 const base::string16& object_id, |
(...skipping 23 matching lines...) Expand all Loading... |
353 | 353 |
354 HRESULT GetFileStreamForObject(IPortableDevice* device, | 354 HRESULT GetFileStreamForObject(IPortableDevice* device, |
355 const base::string16& file_object_id, | 355 const base::string16& file_object_id, |
356 IStream** file_stream, | 356 IStream** file_stream, |
357 DWORD* optimal_transfer_size) { | 357 DWORD* optimal_transfer_size) { |
358 base::ThreadRestrictions::AssertIOAllowed(); | 358 base::ThreadRestrictions::AssertIOAllowed(); |
359 DCHECK(device); | 359 DCHECK(device); |
360 DCHECK(!file_object_id.empty()); | 360 DCHECK(!file_object_id.empty()); |
361 base::win::ScopedComPtr<IPortableDeviceContent> content = | 361 base::win::ScopedComPtr<IPortableDeviceContent> content = |
362 GetDeviceContent(device); | 362 GetDeviceContent(device); |
363 if (!content.get()) | 363 if (!content.Get()) |
364 return E_FAIL; | 364 return E_FAIL; |
365 | 365 |
366 base::win::ScopedComPtr<IPortableDeviceResources> resources; | 366 base::win::ScopedComPtr<IPortableDeviceResources> resources; |
367 HRESULT hr = content->Transfer(resources.Receive()); | 367 HRESULT hr = content->Transfer(resources.Receive()); |
368 if (FAILED(hr)) | 368 if (FAILED(hr)) |
369 return hr; | 369 return hr; |
370 return resources->GetStream(file_object_id.c_str(), WPD_RESOURCE_DEFAULT, | 370 return resources->GetStream(file_object_id.c_str(), WPD_RESOURCE_DEFAULT, |
371 STGM_READ, optimal_transfer_size, | 371 STGM_READ, optimal_transfer_size, |
372 file_stream); | 372 file_stream); |
373 } | 373 } |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
409 object_entries.empty()) | 409 object_entries.empty()) |
410 return base::string16(); | 410 return base::string16(); |
411 // TODO(thestig): This DCHECK can fail. Multiple MTP objects can have | 411 // TODO(thestig): This DCHECK can fail. Multiple MTP objects can have |
412 // the same name. Handle the situation gracefully. Refer to crbug.com/169930 | 412 // the same name. Handle the situation gracefully. Refer to crbug.com/169930 |
413 // for more details. | 413 // for more details. |
414 DCHECK_EQ(1U, object_entries.size()); | 414 DCHECK_EQ(1U, object_entries.size()); |
415 return object_entries[0].object_id; | 415 return object_entries[0].object_id; |
416 } | 416 } |
417 | 417 |
418 } // namespace media_transfer_protocol | 418 } // namespace media_transfer_protocol |
OLD | NEW |