summaryrefslogtreecommitdiffstats
path: root/Modules
diff options
context:
space:
mode:
authorSteve Dower <steve.dower@python.org>2021-07-08 15:48:42 (GMT)
committerGitHub <noreply@github.com>2021-07-08 15:48:42 (GMT)
commitbbf2fb6c7ae78f40483606f467739a58cd747270 (patch)
tree3eeea60d9734f96f979017a3b09beb0a9ca5417f /Modules
parentaf4a2dcc40321de49bffec80bf6c6b5a7d43b134 (diff)
downloadcpython-bbf2fb6c7ae78f40483606f467739a58cd747270.zip
cpython-bbf2fb6c7ae78f40483606f467739a58cd747270.tar.gz
cpython-bbf2fb6c7ae78f40483606f467739a58cd747270.tar.bz2
bpo-44582: Accelerate mimetypes.init on Windows with a native accelerator (GH-27059)
Diffstat (limited to 'Modules')
-rw-r--r--Modules/_winapi.c108
-rw-r--r--Modules/clinic/_winapi.c.h38
2 files changed, 145 insertions, 1 deletions
diff --git a/Modules/_winapi.c b/Modules/_winapi.c
index 1b85d7d..f341493 100644
--- a/Modules/_winapi.c
+++ b/Modules/_winapi.c
@@ -1894,6 +1894,113 @@ _winapi_GetFileType_impl(PyObject *module, HANDLE handle)
return result;
}
+/*[clinic input]
+_winapi._mimetypes_read_windows_registry
+
+ on_type_read: object
+
+Optimized function for reading all known MIME types from the registry.
+
+*on_type_read* is a callable taking *type* and *ext* arguments, as for
+MimeTypes.add_type.
+[clinic start generated code]*/
+
+static PyObject *
+_winapi__mimetypes_read_windows_registry_impl(PyObject *module,
+ PyObject *on_type_read)
+/*[clinic end generated code: output=20829f00bebce55b input=cd357896d6501f68]*/
+{
+#define CCH_EXT 128
+#define CB_TYPE 510
+ struct {
+ wchar_t ext[CCH_EXT];
+ wchar_t type[CB_TYPE / sizeof(wchar_t) + 1];
+ } entries[64];
+ int entry = 0;
+ HKEY hkcr = NULL;
+ LRESULT err;
+
+ Py_BEGIN_ALLOW_THREADS
+ err = RegOpenKeyExW(HKEY_CLASSES_ROOT, NULL, 0, KEY_READ, &hkcr);
+ for (DWORD i = 0; err == ERROR_SUCCESS || err == ERROR_MORE_DATA; ++i) {
+ LPWSTR ext = entries[entry].ext;
+ LPWSTR type = entries[entry].type;
+ DWORD cchExt = CCH_EXT;
+ DWORD cbType = CB_TYPE;
+ HKEY subkey;
+ DWORD regType;
+
+ err = RegEnumKeyExW(hkcr, i, ext, &cchExt, NULL, NULL, NULL, NULL);
+ if (err != ERROR_SUCCESS || (cchExt && ext[0] != L'.')) {
+ continue;
+ }
+
+ err = RegOpenKeyExW(hkcr, ext, 0, KEY_READ, &subkey);
+ if (err == ERROR_FILE_NOT_FOUND) {
+ err = ERROR_SUCCESS;
+ continue;
+ } else if (err != ERROR_SUCCESS) {
+ continue;
+ }
+
+ err = RegQueryValueExW(subkey, L"Content Type", NULL,
+ &regType, (LPBYTE)type, &cbType);
+ RegCloseKey(subkey);
+ if (err == ERROR_FILE_NOT_FOUND) {
+ err = ERROR_SUCCESS;
+ continue;
+ } else if (err != ERROR_SUCCESS) {
+ continue;
+ } else if (regType != REG_SZ || !cbType) {
+ continue;
+ }
+ type[cbType / sizeof(wchar_t)] = L'\0';
+
+ entry += 1;
+
+ /* Flush our cached entries if we are full */
+ if (entry == sizeof(entries) / sizeof(entries[0])) {
+ Py_BLOCK_THREADS
+ for (int j = 0; j < entry; ++j) {
+ PyObject *r = PyObject_CallFunction(
+ on_type_read, "uu", entries[j].type, entries[j].ext
+ );
+ if (!r) {
+ /* We blocked threads, so safe to return from here */
+ RegCloseKey(hkcr);
+ return NULL;
+ }
+ Py_DECREF(r);
+ }
+ Py_UNBLOCK_THREADS
+ entry = 0;
+ }
+ }
+ if (hkcr) {
+ RegCloseKey(hkcr);
+ }
+ Py_END_ALLOW_THREADS
+
+ if (err != ERROR_SUCCESS && err != ERROR_NO_MORE_ITEMS) {
+ PyErr_SetFromWindowsErr((int)err);
+ return NULL;
+ }
+
+ for (int j = 0; j < entry; ++j) {
+ PyObject *r = PyObject_CallFunction(
+ on_type_read, "uu", entries[j].type, entries[j].ext
+ );
+ if (!r) {
+ return NULL;
+ }
+ Py_DECREF(r);
+ }
+
+ Py_RETURN_NONE;
+#undef CCH_EXT
+#undef CB_TYPE
+}
+
static PyMethodDef winapi_functions[] = {
_WINAPI_CLOSEHANDLE_METHODDEF
@@ -1926,6 +2033,7 @@ static PyMethodDef winapi_functions[] = {
_WINAPI_WRITEFILE_METHODDEF
_WINAPI_GETACP_METHODDEF
_WINAPI_GETFILETYPE_METHODDEF
+ _WINAPI__MIMETYPES_READ_WINDOWS_REGISTRY_METHODDEF
{NULL, NULL}
};
diff --git a/Modules/clinic/_winapi.c.h b/Modules/clinic/_winapi.c.h
index a9630d5..5bda156 100644
--- a/Modules/clinic/_winapi.c.h
+++ b/Modules/clinic/_winapi.c.h
@@ -1148,4 +1148,40 @@ _winapi_GetFileType(PyObject *module, PyObject *const *args, Py_ssize_t nargs, P
exit:
return return_value;
}
-/*[clinic end generated code: output=1f10e03f64ff9777 input=a9049054013a1b77]*/
+
+PyDoc_STRVAR(_winapi__mimetypes_read_windows_registry__doc__,
+"_mimetypes_read_windows_registry($module, /, on_type_read)\n"
+"--\n"
+"\n"
+"Optimized function for reading all known MIME types from the registry.\n"
+"\n"
+"*on_type_read* is a callable taking *type* and *ext* arguments, as for\n"
+"MimeTypes.add_type.");
+
+#define _WINAPI__MIMETYPES_READ_WINDOWS_REGISTRY_METHODDEF \
+ {"_mimetypes_read_windows_registry", (PyCFunction)(void(*)(void))_winapi__mimetypes_read_windows_registry, METH_FASTCALL|METH_KEYWORDS, _winapi__mimetypes_read_windows_registry__doc__},
+
+static PyObject *
+_winapi__mimetypes_read_windows_registry_impl(PyObject *module,
+ PyObject *on_type_read);
+
+static PyObject *
+_winapi__mimetypes_read_windows_registry(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
+{
+ PyObject *return_value = NULL;
+ static const char * const _keywords[] = {"on_type_read", NULL};
+ static _PyArg_Parser _parser = {NULL, _keywords, "_mimetypes_read_windows_registry", 0};
+ PyObject *argsbuf[1];
+ PyObject *on_type_read;
+
+ args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 1, 0, argsbuf);
+ if (!args) {
+ goto exit;
+ }
+ on_type_read = args[0];
+ return_value = _winapi__mimetypes_read_windows_registry_impl(module, on_type_read);
+
+exit:
+ return return_value;
+}
+/*[clinic end generated code: output=ac3623be6e42017c input=a9049054013a1b77]*/