mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
WPD: Implement non bulk filesystem metadata transfers for devices that do not support bulk transfers
This commit is contained in:
parent
3a757cd54c
commit
2fd79d209f
16
src/calibre/devices/mtp/filesystem_cache.py
Normal file
16
src/calibre/devices/mtp/filesystem_cache.py
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:fdm=marker:ai
|
||||||
|
from __future__ import (unicode_literals, division, absolute_import,
|
||||||
|
print_function)
|
||||||
|
|
||||||
|
__license__ = 'GPL v3'
|
||||||
|
__copyright__ = '2012, Kovid Goyal <kovid at kovidgoyal.net>'
|
||||||
|
__docformat__ = 'restructuredtext en'
|
||||||
|
|
||||||
|
class FilesystemCache(object):
|
||||||
|
|
||||||
|
def __init__(self, storage_map):
|
||||||
|
self.tree = {}
|
||||||
|
for storage_id, id_map in storage_map.iteritems():
|
||||||
|
self.tree[storage_id] = self.build_tree(id_map)
|
||||||
|
|
@ -87,8 +87,25 @@ static void set_content_type_property(PyObject *dict, IPortableDeviceValues *pro
|
|||||||
if (SUCCEEDED(properties->GetGuidValue(WPD_OBJECT_CONTENT_TYPE, &guid)) && IsEqualGUID(guid, WPD_CONTENT_TYPE_FOLDER)) is_folder = 1;
|
if (SUCCEEDED(properties->GetGuidValue(WPD_OBJECT_CONTENT_TYPE, &guid)) && IsEqualGUID(guid, WPD_CONTENT_TYPE_FOLDER)) is_folder = 1;
|
||||||
PyDict_SetItemString(dict, "is_folder", (is_folder) ? Py_True : Py_False);
|
PyDict_SetItemString(dict, "is_folder", (is_folder) ? Py_True : Py_False);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void set_properties(PyObject *obj, IPortableDeviceValues *values) {
|
||||||
|
set_content_type_property(obj, values);
|
||||||
|
|
||||||
|
set_string_property(obj, WPD_OBJECT_PARENT_ID, "parent_id", values);
|
||||||
|
set_string_property(obj, WPD_OBJECT_NAME, "name", values);
|
||||||
|
set_string_property(obj, WPD_OBJECT_SYNC_ID, "sync_id", values);
|
||||||
|
set_string_property(obj, WPD_OBJECT_PERSISTENT_UNIQUE_ID, "persistent_id", values);
|
||||||
|
|
||||||
|
set_bool_property(obj, WPD_OBJECT_ISHIDDEN, "is_hidden", values);
|
||||||
|
set_bool_property(obj, WPD_OBJECT_CAN_DELETE, "can_delete", values);
|
||||||
|
set_bool_property(obj, WPD_OBJECT_ISSYSTEM, "is_system", values);
|
||||||
|
|
||||||
|
set_size_property(obj, WPD_OBJECT_SIZE, "size", values);
|
||||||
|
}
|
||||||
|
|
||||||
// }}}
|
// }}}
|
||||||
|
|
||||||
|
// Bulk get filesystem {{{
|
||||||
class GetBulkCallback : public IPortableDevicePropertiesBulkCallback {
|
class GetBulkCallback : public IPortableDevicePropertiesBulkCallback {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@ -154,19 +171,8 @@ public:
|
|||||||
}
|
}
|
||||||
Py_DECREF(temp);
|
Py_DECREF(temp);
|
||||||
|
|
||||||
set_content_type_property(obj, properties);
|
set_properties(obj, properties);
|
||||||
|
|
||||||
set_string_property(obj, WPD_OBJECT_PARENT_ID, "parent_id", properties);
|
|
||||||
set_string_property(obj, WPD_OBJECT_NAME, "name", properties);
|
|
||||||
set_string_property(obj, WPD_OBJECT_SYNC_ID, "sync_id", properties);
|
|
||||||
set_string_property(obj, WPD_OBJECT_PERSISTENT_UNIQUE_ID, "persistent_id", properties);
|
|
||||||
|
|
||||||
set_bool_property(obj, WPD_OBJECT_ISHIDDEN, "is_hidden", properties);
|
|
||||||
set_bool_property(obj, WPD_OBJECT_CAN_DELETE, "can_delete", properties);
|
|
||||||
set_bool_property(obj, WPD_OBJECT_ISSYSTEM, "is_system", properties);
|
|
||||||
|
|
||||||
set_size_property(obj, WPD_OBJECT_SIZE, "size", properties);
|
|
||||||
|
|
||||||
properties->Release(); properties = NULL;
|
properties->Release(); properties = NULL;
|
||||||
}
|
}
|
||||||
} // end for loop
|
} // end for loop
|
||||||
@ -240,6 +246,9 @@ end:
|
|||||||
return folders;
|
return folders;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// }}}
|
||||||
|
|
||||||
|
// find_all_objects_in() {{{
|
||||||
static BOOL find_all_objects_in(IPortableDeviceContent *content, IPortableDevicePropVariantCollection *object_ids, const wchar_t *parent_id) {
|
static BOOL find_all_objects_in(IPortableDeviceContent *content, IPortableDevicePropVariantCollection *object_ids, const wchar_t *parent_id) {
|
||||||
/*
|
/*
|
||||||
* Find all children of the object identified by parent_id, recursively.
|
* Find all children of the object identified by parent_id, recursively.
|
||||||
@ -286,8 +295,81 @@ end:
|
|||||||
if (children != NULL) children->Release();
|
if (children != NULL) children->Release();
|
||||||
PropVariantClear(&pv);
|
PropVariantClear(&pv);
|
||||||
return ok;
|
return ok;
|
||||||
|
} // }}}
|
||||||
|
|
||||||
|
// Single get filesystem {{{
|
||||||
|
|
||||||
|
static PyObject* get_object_properties(IPortableDeviceProperties *devprops, IPortableDeviceKeyCollection *properties, const wchar_t *object_id) {
|
||||||
|
IPortableDeviceValues *values = NULL;
|
||||||
|
HRESULT hr;
|
||||||
|
PyObject *ans = NULL, *temp = NULL;
|
||||||
|
|
||||||
|
Py_BEGIN_ALLOW_THREADS;
|
||||||
|
hr = devprops->GetValues(object_id, properties, &values);
|
||||||
|
Py_END_ALLOW_THREADS;
|
||||||
|
if (FAILED(hr)) { hresult_set_exc("Failed to get properties for object", hr); goto end; }
|
||||||
|
|
||||||
|
temp = wchar_to_unicode(object_id);
|
||||||
|
if (temp == NULL) goto end;
|
||||||
|
|
||||||
|
ans = PyDict_New();
|
||||||
|
if (ans == NULL) { PyErr_NoMemory(); goto end; }
|
||||||
|
if (PyDict_SetItemString(ans, "id", temp) != 0) { Py_DECREF(ans); ans = NULL; PyErr_NoMemory(); goto end; }
|
||||||
|
|
||||||
|
set_properties(ans, values);
|
||||||
|
|
||||||
|
end:
|
||||||
|
Py_XDECREF(temp);
|
||||||
|
if (values != NULL) values->Release();
|
||||||
|
return ans;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static PyObject* single_get_filesystem(IPortableDeviceContent *content, const wchar_t *storage_id, IPortableDevicePropVariantCollection *object_ids) {
|
||||||
|
DWORD num, i;
|
||||||
|
PROPVARIANT pv;
|
||||||
|
HRESULT hr;
|
||||||
|
BOOL ok = 1;
|
||||||
|
PyObject *ans = NULL, *item = NULL;
|
||||||
|
IPortableDeviceProperties *devprops = NULL;
|
||||||
|
IPortableDeviceKeyCollection *properties = NULL;
|
||||||
|
|
||||||
|
hr = content->Properties(&devprops);
|
||||||
|
if (FAILED(hr)) { hresult_set_exc("Failed to get IPortableDeviceProperties interface", hr); goto end; }
|
||||||
|
|
||||||
|
properties = create_filesystem_properties_collection();
|
||||||
|
if (properties == NULL) goto end;
|
||||||
|
|
||||||
|
hr = object_ids->GetCount(&num);
|
||||||
|
if (FAILED(hr)) { hresult_set_exc("Failed to get object id count", hr); goto end; }
|
||||||
|
|
||||||
|
ans = PyDict_New();
|
||||||
|
if (ans == NULL) goto end;
|
||||||
|
|
||||||
|
for (i = 0; i < num; i++) {
|
||||||
|
ok = 0;
|
||||||
|
PropVariantInit(&pv);
|
||||||
|
hr = object_ids->GetAt(i, &pv);
|
||||||
|
if (SUCCEEDED(hr) && pv.pwszVal != NULL) {
|
||||||
|
item = get_object_properties(devprops, properties, pv.pwszVal);
|
||||||
|
if (item != NULL) {
|
||||||
|
PyDict_SetItem(ans, PyDict_GetItemString(item, "id"), item);
|
||||||
|
Py_DECREF(item); item = NULL;
|
||||||
|
ok = 1;
|
||||||
|
}
|
||||||
|
} else hresult_set_exc("Failed to get item from IPortableDevicePropVariantCollection", hr);
|
||||||
|
|
||||||
|
PropVariantClear(&pv);
|
||||||
|
if (!ok) { Py_DECREF(ans); ans = NULL; break; }
|
||||||
|
}
|
||||||
|
|
||||||
|
end:
|
||||||
|
if (devprops != NULL) devprops->Release();
|
||||||
|
if (properties != NULL) properties->Release();
|
||||||
|
|
||||||
|
return ans;
|
||||||
|
}
|
||||||
|
// }}}
|
||||||
|
|
||||||
PyObject* wpd::get_filesystem(IPortableDevice *device, const wchar_t *storage_id, IPortableDevicePropertiesBulk *bulk_properties) {
|
PyObject* wpd::get_filesystem(IPortableDevice *device, const wchar_t *storage_id, IPortableDevicePropertiesBulk *bulk_properties) {
|
||||||
PyObject *folders = NULL;
|
PyObject *folders = NULL;
|
||||||
IPortableDevicePropVariantCollection *object_ids = NULL;
|
IPortableDevicePropVariantCollection *object_ids = NULL;
|
||||||
@ -310,6 +392,7 @@ PyObject* wpd::get_filesystem(IPortableDevice *device, const wchar_t *storage_id
|
|||||||
if (!ok) goto end;
|
if (!ok) goto end;
|
||||||
|
|
||||||
if (bulk_properties != NULL) folders = bulk_get_filesystem(device, bulk_properties, storage_id, object_ids);
|
if (bulk_properties != NULL) folders = bulk_get_filesystem(device, bulk_properties, storage_id, object_ids);
|
||||||
|
else folders = single_get_filesystem(content, storage_id, object_ids);
|
||||||
|
|
||||||
end:
|
end:
|
||||||
if (content != NULL) content->Release();
|
if (content != NULL) content->Release();
|
||||||
|
@ -50,7 +50,7 @@ extern PyTypeObject DeviceType;
|
|||||||
// Utility functions
|
// Utility functions
|
||||||
PyObject *hresult_set_exc(const char *msg, HRESULT hr);
|
PyObject *hresult_set_exc(const char *msg, HRESULT hr);
|
||||||
wchar_t *unicode_to_wchar(PyObject *o);
|
wchar_t *unicode_to_wchar(PyObject *o);
|
||||||
PyObject *wchar_to_unicode(wchar_t *o);
|
PyObject *wchar_to_unicode(const wchar_t *o);
|
||||||
int pump_waiting_messages();
|
int pump_waiting_messages();
|
||||||
|
|
||||||
extern IPortableDeviceValues* get_client_information();
|
extern IPortableDeviceValues* get_client_information();
|
||||||
|
@ -43,7 +43,7 @@ wchar_t *wpd::unicode_to_wchar(PyObject *o) {
|
|||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
PyObject *wpd::wchar_to_unicode(wchar_t *o) {
|
PyObject *wpd::wchar_to_unicode(const wchar_t *o) {
|
||||||
PyObject *ans;
|
PyObject *ans;
|
||||||
if (o == NULL) return NULL;
|
if (o == NULL) return NULL;
|
||||||
ans = PyUnicode_FromWideChar(o, wcslen(o));
|
ans = PyUnicode_FromWideChar(o, wcslen(o));
|
||||||
|
Loading…
x
Reference in New Issue
Block a user