Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit927b5af

Browse files
zoobaaisk
andauthored
bpo-42658: Use LCMapStringEx in ntpath.normcase to match OS behaviour for case-folding (GH-93591)
*bpo-42658: Use LCMapStringEx in ntpath.normcase to match OS behaviour for case-folding (GH-32010)* Use AsWideCharString to avoid memory leaks in deprectated unicode converterCo-authored-by: AN Long <aisk@users.noreply.github.com>
1 parentf384a8e commit927b5af

File tree

5 files changed

+151
-9
lines changed

5 files changed

+151
-9
lines changed

‎Lib/ntpath.py‎

Lines changed: 34 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
importgenericpath
2424
fromgenericpathimport*
2525

26+
2627
__all__= ["normcase","isabs","join","splitdrive","split","splitext",
2728
"basename","dirname","commonprefix","getsize","getmtime",
2829
"getatime","getctime","islink","exists","lexists","isdir","isfile",
@@ -41,14 +42,39 @@ def _get_bothseps(path):
4142
# Other normalizations (such as optimizing '../' away) are not done
4243
# (this is done by normpath).
4344

44-
defnormcase(s):
45-
"""Normalize case of pathname.
46-
47-
Makes all characters lowercase and all slashes into backslashes."""
48-
s=os.fspath(s)
49-
ifisinstance(s,bytes):
50-
returns.replace(b'/',b'\\').lower()
51-
else:
45+
try:
46+
from_winapiimport (
47+
LCMapStringExas_LCMapStringEx,
48+
LOCALE_NAME_INVARIANTas_LOCALE_NAME_INVARIANT,
49+
LCMAP_LOWERCASEas_LCMAP_LOWERCASE)
50+
51+
defnormcase(s):
52+
"""Normalize case of pathname.
53+
54+
Makes all characters lowercase and all slashes into backslashes.
55+
"""
56+
s=os.fspath(s)
57+
ifnots:
58+
returns
59+
ifisinstance(s,bytes):
60+
encoding=sys.getfilesystemencoding()
61+
s=s.decode(encoding,'surrogateescape').replace('/','\\')
62+
s=_LCMapStringEx(_LOCALE_NAME_INVARIANT,
63+
_LCMAP_LOWERCASE,s)
64+
returns.encode(encoding,'surrogateescape')
65+
else:
66+
return_LCMapStringEx(_LOCALE_NAME_INVARIANT,
67+
_LCMAP_LOWERCASE,
68+
s.replace('/','\\'))
69+
exceptImportError:
70+
defnormcase(s):
71+
"""Normalize case of pathname.
72+
73+
Makes all characters lowercase and all slashes into backslashes.
74+
"""
75+
s=os.fspath(s)
76+
ifisinstance(s,bytes):
77+
returnos.fsencode(os.fsdecode(s).replace('/','\\').lower())
5278
returns.replace('/','\\').lower()
5379

5480

‎Lib/test/test_ntpath.py‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -852,6 +852,8 @@ def _check_function(self, func):
852852

853853
deftest_path_normcase(self):
854854
self._check_function(self.path.normcase)
855+
ifsys.platform=='win32':
856+
self.assertEqual(ntpath.normcase('\u03a9\u2126'),'ωΩ')
855857

856858
deftest_path_isabs(self):
857859
self._check_function(self.path.isabs)
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Support native Windows case-insensitive path comparisons by using
2+
``LCMapStringEx`` instead of:func:`str.lower` in:func:`ntpath.normcase`.
3+
Add ``LCMapStringEx`` to the:mod:`_winapi` module.

‎Modules/_winapi.c‎

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1512,6 +1512,68 @@ _winapi_PeekNamedPipe_impl(PyObject *module, HANDLE handle, int size)
15121512
}
15131513
}
15141514

1515+
/*[clinic input]
1516+
_winapi.LCMapStringEx
1517+
1518+
locale: unicode
1519+
flags: DWORD
1520+
src: unicode
1521+
1522+
[clinic start generated code]*/
1523+
1524+
staticPyObject*
1525+
_winapi_LCMapStringEx_impl(PyObject*module,PyObject*locale,DWORDflags,
1526+
PyObject*src)
1527+
/*[clinic end generated code: output=8ea4c9d85a4a1f23 input=2fa6ebc92591731b]*/
1528+
{
1529+
if (flags& (LCMAP_SORTHANDLE |LCMAP_HASH |LCMAP_BYTEREV |
1530+
LCMAP_SORTKEY)) {
1531+
returnPyErr_Format(PyExc_ValueError,"unsupported flags");
1532+
}
1533+
1534+
wchar_t*locale_=PyUnicode_AsWideCharString(locale,NULL);
1535+
if (!locale_) {
1536+
returnNULL;
1537+
}
1538+
wchar_t*src_=PyUnicode_AsWideCharString(src,NULL);
1539+
if (!src_) {
1540+
PyMem_Free(locale_);
1541+
returnNULL;
1542+
}
1543+
1544+
intdest_size=LCMapStringEx(locale_,flags,src_,-1,NULL,0,
1545+
NULL,NULL,0);
1546+
if (dest_size==0) {
1547+
PyMem_Free(locale_);
1548+
PyMem_Free(src_);
1549+
returnPyErr_SetFromWindowsErr(0);
1550+
}
1551+
1552+
wchar_t*dest=PyMem_NEW(wchar_t,dest_size);
1553+
if (dest==NULL) {
1554+
PyMem_Free(locale_);
1555+
PyMem_Free(src_);
1556+
returnPyErr_NoMemory();
1557+
}
1558+
1559+
intnmapped=LCMapStringEx(locale_,flags,src_,-1,dest,dest_size,
1560+
NULL,NULL,0);
1561+
if (nmapped==0) {
1562+
DWORDerror=GetLastError();
1563+
PyMem_Free(locale_);
1564+
PyMem_Free(src_);
1565+
PyMem_DEL(dest);
1566+
returnPyErr_SetFromWindowsErr(error);
1567+
}
1568+
1569+
PyObject*ret=PyUnicode_FromWideChar(dest,dest_size-1);
1570+
PyMem_Free(locale_);
1571+
PyMem_Free(src_);
1572+
PyMem_DEL(dest);
1573+
1574+
returnret;
1575+
}
1576+
15151577
/*[clinic input]
15161578
_winapi.ReadFile
15171579
@@ -2023,6 +2085,7 @@ static PyMethodDef winapi_functions[] = {
20232085
_WINAPI_OPENFILEMAPPING_METHODDEF
20242086
_WINAPI_OPENPROCESS_METHODDEF
20252087
_WINAPI_PEEKNAMEDPIPE_METHODDEF
2088+
_WINAPI_LCMAPSTRINGEX_METHODDEF
20262089
_WINAPI_READFILE_METHODDEF
20272090
_WINAPI_SETNAMEDPIPEHANDLESTATE_METHODDEF
20282091
_WINAPI_TERMINATEPROCESS_METHODDEF
@@ -2160,6 +2223,22 @@ static int winapi_exec(PyObject *m)
21602223
WINAPI_CONSTANT(F_DWORD,FILE_TYPE_PIPE);
21612224
WINAPI_CONSTANT(F_DWORD,FILE_TYPE_REMOTE);
21622225

2226+
WINAPI_CONSTANT("u",LOCALE_NAME_INVARIANT);
2227+
WINAPI_CONSTANT(F_DWORD,LOCALE_NAME_MAX_LENGTH);
2228+
WINAPI_CONSTANT("u",LOCALE_NAME_SYSTEM_DEFAULT);
2229+
WINAPI_CONSTANT("u",LOCALE_NAME_USER_DEFAULT);
2230+
2231+
WINAPI_CONSTANT(F_DWORD,LCMAP_FULLWIDTH);
2232+
WINAPI_CONSTANT(F_DWORD,LCMAP_HALFWIDTH);
2233+
WINAPI_CONSTANT(F_DWORD,LCMAP_HIRAGANA);
2234+
WINAPI_CONSTANT(F_DWORD,LCMAP_KATAKANA);
2235+
WINAPI_CONSTANT(F_DWORD,LCMAP_LINGUISTIC_CASING);
2236+
WINAPI_CONSTANT(F_DWORD,LCMAP_LOWERCASE);
2237+
WINAPI_CONSTANT(F_DWORD,LCMAP_SIMPLIFIED_CHINESE);
2238+
WINAPI_CONSTANT(F_DWORD,LCMAP_TITLECASE);
2239+
WINAPI_CONSTANT(F_DWORD,LCMAP_TRADITIONAL_CHINESE);
2240+
WINAPI_CONSTANT(F_DWORD,LCMAP_UPPERCASE);
2241+
21632242
WINAPI_CONSTANT("i",NULL);
21642243

21652244
return0;

‎Modules/clinic/_winapi.c.h‎

Lines changed: 33 additions & 1 deletion
Some generated files are not rendered by default. Learn more aboutcustomizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp