diff options
author | Steve Dower <steve.dower@python.org> | 2021-07-08 15:48:42 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-07-08 15:48:42 (GMT) |
commit | bbf2fb6c7ae78f40483606f467739a58cd747270 (patch) | |
tree | 3eeea60d9734f96f979017a3b09beb0a9ca5417f /Modules | |
parent | af4a2dcc40321de49bffec80bf6c6b5a7d43b134 (diff) | |
download | cpython-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.c | 108 | ||||
-rw-r--r-- | Modules/clinic/_winapi.c.h | 38 |
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, + ®Type, (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]*/ |