Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replace usage of old unicode API removed in Py3.12/PEP 623 #1860

Merged
merged 4 commits into from
Sep 17, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 8 additions & 3 deletions Pythonwin/win32util.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1137,8 +1137,8 @@ CString GetReprText(PyObject *objectUse)
PyObject *s;
CString csRet;
s = PyObject_Str(objectUse);
if (s) {
csRet = CString(PyUnicode_AsUnicode(s));
if (s) if (TmpWCHAR ts=s) {
csRet = CString(ts);
Py_DECREF(s);
return csRet;
}
Expand All @@ -1152,7 +1152,12 @@ CString GetReprText(PyObject *objectUse)

// repr() should always return a unicode string, but for hysterical raisens we check if it is bytes.
if (PyUnicode_Check(s))
csRet = CString(PyUnicode_AS_UNICODE(s));
if (TmpWCHAR ts=s)
csRet = ts;
else {
PyErr_Clear();
csRet = L"??? wide string allocation error ???";
}
else if (PyBytes_Check(s))
csRet = CString(PyBytes_AS_STRING(s));
else
Expand Down
6 changes: 2 additions & 4 deletions Pythonwin/win32virt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -117,11 +117,9 @@ BOOL CVirtualHelper::do_call(PyObject *args)
if (obRepr) {
if (PyBytes_Check(obRepr))
szRepr = PyBytes_AS_STRING(obRepr);
else if (PyUnicode_Check(obRepr))
szRepr = W2A(PyUnicode_AS_UNICODE(obRepr));
else if (TmpWCHAR tmpw=obRepr)
szRepr = W2A(tmpw);
}
else
PyErr_Clear();

LPTSTR HandlerName = csHandlerName.GetBuffer(csHandlerName.GetLength());
snprintf(msg, sizeof(msg) / sizeof(msg[0]), "%s() virtual handler (%s) raised an exception",
Expand Down
5 changes: 3 additions & 2 deletions com/win32com/src/extensions/PySTGMEDIUM.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ PyObject *PySet(PyObject *self, PyObject *args)
}
case TYMED_HGLOBAL: {
const void *buf = NULL;
TmpWCHAR tmpw;
Py_ssize_t cb = 0;
PyWinBufferView pybuf;
// In py3k, unicode objects don't support the buffer
Expand All @@ -62,8 +63,8 @@ PyObject *PySet(PyObject *self, PyObject *args)
buf = (void *)PyBytes_AS_STRING(ob);
}
else if (PyUnicode_Check(ob)) {
cb = PyUnicode_GET_DATA_SIZE(ob) + sizeof(Py_UNICODE);
buf = (void *)PyUnicode_AS_UNICODE(ob);
buf = tmpw = ob; if (!tmpw) return NULL;
cb = (tmpw.length + 1) * sizeof(WCHAR);
}
else {
if (!pybuf.init(ob))
Expand Down
13 changes: 8 additions & 5 deletions isapi/src/PyExtensionObjects.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,12 @@

//#define PY_SSIZE_T_CLEAN // defined by isapi\src\StdAfx.h
#include "stdafx.h"
#include "pywintypes.h"
#include "Utils.h"
#include "PyExtensionObjects.h"
#include "PythonEng.h"


// Asynch IO callbacks are a little tricky, as we never know how many
// callbacks a single connection might make (often each callback will trigger
// another IO request.) So we keep the Python objects used by the callback
Expand Down Expand Up @@ -174,7 +176,7 @@ PyObject *PyVERSION_INFO::getattro(PyObject *self, PyObject *obname)
PyVERSION_INFO *me = (PyVERSION_INFO *)self;
if (!me->m_pvi)
return PyErr_Format(PyExc_RuntimeError, "VERSION_INFO structure no longer exists");
TCHAR *name = PYISAPI_ATTR_CONVERT(obname);
TmpWCHAR name = obname; if (!name) return NULL;
if (_tcscmp(name, _T("ExtensionDesc")) == 0) {
return PyBytes_FromString(me->m_pvi->lpszExtensionDesc);
}
Expand All @@ -184,7 +186,7 @@ PyObject *PyVERSION_INFO::getattro(PyObject *self, PyObject *obname)
int PyVERSION_INFO::setattro(PyObject *self, PyObject *obname, PyObject *v)
{
PyVERSION_INFO *me = (PyVERSION_INFO *)self;
TCHAR *name = PYISAPI_ATTR_CONVERT(obname);
TmpWCHAR name = obname; if (!name) return -1;
if (!me->m_pvi) {
PyErr_Format(PyExc_RuntimeError, "VERSION_INFO structure no longer exists");
return -1;
Expand Down Expand Up @@ -343,7 +345,7 @@ PyECB::~PyECB()

PyObject *PyECB::getattro(PyObject *self, PyObject *obname)
{
TCHAR *name = PYISAPI_ATTR_CONVERT(obname);
TmpWCHAR name = obname; if (!name) return NULL;

if (_tcscmp(name, _T("softspace")) == 0) // help 'print' semantics.
return PyLong_FromLong(1);
Expand Down Expand Up @@ -383,7 +385,7 @@ int PyECB::setattro(PyObject *self, PyObject *obname, PyObject *v)
PyErr_SetString(PyExc_AttributeError, "can't delete ECB attributes");
return -1;
}
TCHAR *name = PYISAPI_ATTR_CONVERT(obname);
TmpWCHAR name = obname; if (!name) return -1;

if (_tcscmp(name, _T("HttpStatusCode")) == 0) {
PyECB *pecb = (PyECB *)self;
Expand Down Expand Up @@ -681,8 +683,9 @@ PyObject *PyECB::GetAnonymousToken(PyObject *self, PyObject *args)
Py_END_ALLOW_THREADS
}
else if (PyUnicode_Check(obStr)) {
TmpWCHAR tmpw = obStr; if (!tmpw) return NULL;
Py_BEGIN_ALLOW_THREADS bRes = ecb->ServerSupportFunction(ecb->ConnID, HSE_REQ_GET_UNICODE_ANONYMOUS_TOKEN,
PyUnicode_AS_UNICODE(obStr), (DWORD *)&handle, NULL);
tmpw, (DWORD *)&handle, NULL);
Py_END_ALLOW_THREADS
}
else
Expand Down
27 changes: 14 additions & 13 deletions isapi/src/PyFilterObjects.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@

//#define PY_SSIZE_T_CLEAN // defined by isapi\src\StdAfx.h
#include "stdafx.h"
#include "pywintypes.h"
#include "Utils.h"
#include "pyFilterObjects.h"

Expand Down Expand Up @@ -68,7 +69,7 @@ PyObject *PyFILTER_VERSION::getattro(PyObject *self, PyObject *obname)
PyFILTER_VERSION *me = (PyFILTER_VERSION *)self;
if (!me->m_pfv)
return PyErr_Format(PyExc_RuntimeError, "FILTER_VERSION structure no longer exists");
TCHAR *name = PYISAPI_ATTR_CONVERT(obname);
TmpWCHAR name = obname; if (!name) return NULL;
// @prop int|ServerFilterVersion|(read-only)
if (_tcscmp(name, _T("ServerFilterVersion")) == 0) {
return PyLong_FromLong(me->m_pfv->dwServerFilterVersion);
Expand All @@ -85,7 +86,7 @@ PyObject *PyFILTER_VERSION::getattro(PyObject *self, PyObject *obname)
if (_tcscmp(name, _T("FilterDesc")) == 0) {
return PyBytes_FromString(me->m_pfv->lpszFilterDesc);
}
return PyErr_Format(PyExc_AttributeError, "PyFILTER_VERSION has no attribute '%s'", name);
return PyErr_Format(PyExc_AttributeError, "PyFILTER_VERSION has no attribute '%S'", obname);
}

int PyFILTER_VERSION::setattro(PyObject *self, PyObject *obname, PyObject *v)
Expand All @@ -99,7 +100,7 @@ int PyFILTER_VERSION::setattro(PyObject *self, PyObject *obname, PyObject *v)
PyErr_SetString(PyExc_AttributeError, "can't delete FILTER_VERSION attributes");
return -1;
}
TCHAR *name = PYISAPI_ATTR_CONVERT(obname);
TmpWCHAR name = obname; if (!name) return -1;
if (_tcscmp(name, _T("FilterVersion")) == 0) {
if (!PyLong_Check(v)) {
PyErr_Format(PyExc_ValueError, "FilterVersion must be an int (got %s)", v->ob_type->tp_name);
Expand Down Expand Up @@ -415,7 +416,7 @@ PyHFC::~PyHFC()

PyObject *PyHFC::getattro(PyObject *self, PyObject *obname)
{
TCHAR *name = PYISAPI_ATTR_CONVERT(obname);
TmpWCHAR name = obname; if (!name) return NULL;

// other manual attributes.
if (_tcscmp(name, _T("FilterContext")) == 0) {
Expand All @@ -434,7 +435,7 @@ PyObject *PyHFC::getattro(PyObject *self, PyObject *obname)

int PyHFC::setattro(PyObject *self, PyObject *obname, PyObject *v)
{
TCHAR *name = PYISAPI_ATTR_CONVERT(obname);
TmpWCHAR name = obname; if (!name) return -1;
if (v == NULL) {
PyErr_SetString(PyExc_AttributeError, "can't delete ECB attributes");
return -1;
Expand Down Expand Up @@ -536,7 +537,7 @@ PyObject *PyURL_MAP::getattro(PyObject *self, PyObject *obname)
if (!pMap)
return NULL;
// @prop string|URL|
TCHAR *name = PYISAPI_ATTR_CONVERT(obname);
TmpWCHAR name = obname; if (!name) return NULL;
if (_tcscmp(name, _T("URL")) == 0) {
return PyBytes_FromString(pMap->pszURL);
}
Expand All @@ -552,7 +553,7 @@ int PyURL_MAP::setattro(PyObject *self, PyObject *obname, PyObject *v)
HTTP_FILTER_URL_MAP *pMap = ((PyURL_MAP *)self)->GetURLMap();
if (!pMap)
return NULL;
TCHAR *name = PYISAPI_ATTR_CONVERT(obname);
TmpWCHAR name = obname; if (!name) return -1;
if (_tcscmp(name, _T("PhysicalPath")) == 0) {
if (!PyBytes_Check(v)) {
PyErr_Format(PyExc_TypeError, "PhysicalPath must be a string");
Expand Down Expand Up @@ -779,7 +780,7 @@ PyObject *PyRAW_DATA::getattro(PyObject *self, PyObject *obname)
if (!pRD)
return NULL;
// @prop string|InData|
TCHAR *name = PYISAPI_ATTR_CONVERT(obname);
TmpWCHAR name = obname; if (!name) return NULL;
if (_tcscmp(name, _T("InData")) == 0) {
if (pRD->pvInData == NULL) {
Py_INCREF(Py_None);
Expand All @@ -799,7 +800,7 @@ int PyRAW_DATA::setattro(PyObject *self, PyObject *obname, PyObject *v)
if (!pRD || !pFC)
return NULL;

TCHAR *name = PYISAPI_ATTR_CONVERT(obname);
TmpWCHAR name = obname; if (!name) return -1;
if (_tcscmp(name, _T("InData")) == 0) {
if (!PyBytes_Check(v)) {
PyErr_Format(PyExc_TypeError, "InData must be a string (got %s)", v->ob_type->tp_name);
Expand Down Expand Up @@ -885,7 +886,7 @@ PyObject *PyAUTHENT::getattro(PyObject *self, PyObject *obname)
HTTP_FILTER_AUTHENT *pAE = ((PyAUTHENT *)self)->GetAUTHENT();
if (!pAE)
return NULL;
TCHAR *name = PYISAPI_ATTR_CONVERT(obname);
TmpWCHAR name = obname; if (!name) return NULL;
// @prop string|User|
if (_tcscmp(name, _T("User")) == 0) {
if (pAE->pszUser == NULL) {
Expand Down Expand Up @@ -913,7 +914,7 @@ int PyAUTHENT::setattro(PyObject *self, PyObject *obname, PyObject *v)
if (!pAE || !pFC)
return NULL;

TCHAR *name = PYISAPI_ATTR_CONVERT(obname);
TmpWCHAR name = obname; if (!name) return -1;
if (_tcscmp(name, _T("User")) == 0) {
if (!PyBytes_Check(v)) {
PyErr_Format(PyExc_TypeError, "User must be a string (got %s)", v->ob_type->tp_name);
Expand Down Expand Up @@ -998,7 +999,7 @@ PyObject *PyFILTER_LOG::getattro(PyObject *self, PyObject *obname)
HTTP_FILTER_LOG *pLog = ((PyFILTER_LOG *)self)->GetFilterLog();
if (!pLog)
return NULL;
TCHAR *name = PYISAPI_ATTR_CONVERT(obname);
TmpWCHAR name = obname; if (!name) return NULL;
// @prop string|ClientHostName|
if (_tcscmp(name, _T("ClientHostName")) == 0)
return PyBytes_FromString(pLog->pszClientHostName);
Expand Down Expand Up @@ -1063,7 +1064,7 @@ int PyFILTER_LOG::setattro(PyObject *self, PyObject *obname, PyObject *v)
HTTP_FILTER_LOG *pLog = ((PyFILTER_LOG *)self)->GetFilterLog();
if (!pLog || !pFC)
return NULL;
TCHAR *name = PYISAPI_ATTR_CONVERT(obname);
TmpWCHAR name = obname; if (!name) return -1;
CHECK_SET_FILTER_LOG_STRING(ClientHostName)
CHECK_SET_FILTER_LOG_STRING(ClientUserName)
CHECK_SET_FILTER_LOG_STRING(ServerName)
Expand Down
2 changes: 2 additions & 0 deletions isapi/src/PythonEng.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ class CPythonHandler {
void ExtensionError(CControlBlock *pcb, const char *errmsg);
void FilterError(CFilterContext *pfc, const char *errmsg);

#ifndef __PYWINTYPES_H__
class CEnterLeavePython {
public:
CEnterLeavePython() : state(PyGILState_Ensure()) { ; }
Expand All @@ -87,5 +88,6 @@ class CEnterLeavePython {
protected:
PyGILState_STATE state;
};
#endif

#endif // __PythonEngine_H
2 changes: 1 addition & 1 deletion isapi/src/StdAfx.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@

// Macros to handle PyObject layout changes in Py3k
#define PYISAPI_OBJECT_HEAD PyVarObject_HEAD_INIT(NULL, 0)
#define PYISAPI_ATTR_CONVERT PyUnicode_AsUnicode
////#define PYISAPI_ATTR_CONVERT PyUnicode_AsUnicode // removed in Py3.12+

// A helper that on py3k takes a str or unicode as input and returns a
// string - exactly how the 's#' PyArg_ParseTuple format string does...
Expand Down
41 changes: 11 additions & 30 deletions win32/src/PyUnicode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ BOOL PyWinObject_AsPfnAllocatedWCHAR(PyObject *stringObject, void *(*pfnAllocato
}
else if (PyUnicode_Check(stringObject)) {
// copy the value, including embedded NULLs
WCHAR *v = (WCHAR *)PyUnicode_AS_UNICODE(stringObject);
Py_ssize_t cch = PyUnicode_GET_SIZE(stringObject);
TmpWCHAR v = stringObject; if (!v) return FALSE;
Py_ssize_t cch = v.length;
*ppResult = (WCHAR *)pfnAllocator((cch + 1) * sizeof(WCHAR));
if (*ppResult)
memcpy(*ppResult, v, (cch + 1) * sizeof(WCHAR));
Expand Down Expand Up @@ -102,11 +102,7 @@ BOOL PyWinObject_AsChars(PyObject *stringObject, char **pResult, BOOL bNoneOK /*
// Convert the string if a WIDE string.
if (PyUnicode_Check(stringObject)) {
// PyUnicode_EncodeMBCS was removed in Py 3.11.
PyObject *unicode = PyUnicode_FromWideChar(PyUnicode_AS_UNICODE(stringObject), -1);
if (unicode == NULL)
return FALSE;
stringObject = tempObject = PyUnicode_EncodeCodePage(CP_ACP, unicode, NULL);
Py_DECREF(unicode);
stringObject = tempObject = PyUnicode_AsMBCSString(stringObject);
if (!stringObject)
return FALSE;
}
Expand Down Expand Up @@ -184,22 +180,11 @@ BOOL PyWinObject_AsBstr(PyObject *stringObject, BSTR *pResult, BOOL bNoneOK /*=
// sane b/w compat reason to support that any more.
if (PyUnicode_Check(stringObject)) {
// copy the value, including embedded NULLs
Py_ssize_t nchars = PyUnicode_GET_SIZE(stringObject);
*pResult = SysAllocStringLen(NULL, nchars);
if (*pResult) {
#define PUAWC_TYPE PyObject *
if (PyUnicode_AsWideChar((PUAWC_TYPE)stringObject, *pResult, nchars) == -1) {
rc = FALSE;
}
else {
// The SysAllocStringLen docs indicate that nchars+1 bytes are allocated,
// and that normally a \0 is appened by the function. It also states
// the \0 is not necessary! While it seems to work fine without it,
// we do copy it, as the previous code, which used SysAllocStringLen
// with a non-NULL arg is documented clearly as appending the \0.
(*pResult)[nchars] = 0;
}
}
// Py3.12+: only conversion yields the correct number of wide chars (incl. surrogate pairs).
// For simplicity we use a temp buffer.
TmpWCHAR tw = stringObject; if (!tw) return FALSE;
// SysAllocStringLen allocates length+1 wchars (and puts a \0 at end); like PyUnicode_AsWideCharString
*pResult = SysAllocStringLen(tw, tw.length);
}
else if (stringObject == Py_None) {
if (bNoneOK) {
Expand Down Expand Up @@ -228,23 +213,19 @@ void PyWinObject_FreeBstr(BSTR str) { SysFreeString(str); }

// String conversions
// Convert a Python object to a WCHAR - allow embedded NULLs, None, etc.
// Must be freed with PyWinObject_FreeWCHAR
// Must be freed with PyWinObject_FreeWCHAR / PyMem_Free
BOOL PyWinObject_AsWCHAR(PyObject *stringObject, WCHAR **pResult, BOOL bNoneOK /*= FALSE*/,
DWORD *pResultLen /*= NULL*/)
{
BOOL rc = TRUE;
Py_ssize_t resultLen = 0;
// Do NOT accept 'bytes' for any 'WCHAR' API.
if (PyUnicode_Check(stringObject)) {
resultLen = PyUnicode_GET_SIZE(stringObject);
size_t cb = sizeof(WCHAR) * (resultLen + 1);
*pResult = (WCHAR *)PyMem_Malloc(cb);
*pResult = PyUnicode_AsWideCharString(stringObject, &resultLen);
if (*pResult == NULL) {
PyErr_SetString(PyExc_MemoryError, "Allocating WCHAR array");
PyErr_SetString(PyExc_MemoryError, "Getting WCHAR string");
return FALSE;
}
// copy the value, including embedded NULLs
memcpy(*pResult, PyUnicode_AsUnicode(stringObject), cb);
}
else if (stringObject == Py_None) {
if (bNoneOK) {
Expand Down
22 changes: 19 additions & 3 deletions win32/src/PyWinTypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -167,19 +167,35 @@ PYWINTYPES_EXPORT void PyWinObject_FreeChars(char *pResult);
// Automatically freed WCHAR that can be used anywhere WCHAR * is required
class TmpWCHAR {
public:
WCHAR *tmp;
WCHAR *tmp; // (NULL after conversion error)
Py_ssize_t length; // only set after successful auto-conversion; w/o trailing \0
TmpWCHAR() { tmp = NULL; }
TmpWCHAR(WCHAR *t) { tmp = t; }
TmpWCHAR(PyObject *ob) : tmp(NULL) { *this = ob; }
WCHAR *operator=(PyObject *ob) {
if (tmp)
PyMem_Free(tmp);
if (ob == NULL)
tmp = NULL; // (exception already has been set in this case)
else
tmp = PyUnicode_AsWideCharString(ob, &length);
return tmp;
}
WCHAR *operator=(WCHAR *t)
{
PyWinObject_FreeWCHAR(tmp);
if (tmp)
PyMem_Free(tmp);
tmp = t;
return t;
}
WCHAR **operator&() { return &tmp; }
boolean operator==(WCHAR *t) { return tmp == t; }
operator WCHAR *() { return tmp; }
~TmpWCHAR() { PyWinObject_FreeWCHAR(tmp); }
~TmpWCHAR() { if (tmp) PyMem_Free(tmp); }
private:
// Block unwanted copy construction
TmpWCHAR(const TmpWCHAR& o); // = delete;
const TmpWCHAR& operator=(const TmpWCHAR& o); // = delete;
};

// More string helpers - how many do we need?
Expand Down
6 changes: 3 additions & 3 deletions win32/src/PythonService.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1463,9 +1463,9 @@ int _tmain(int argc, TCHAR **argv)
// now get the handle to the DLL, and call the main function.
if (PyBytes_Check(f))
hmod = GetModuleHandleA(PyBytes_AsString(f));
else if (PyUnicode_Check(f))
hmod = GetModuleHandleW(PyUnicode_AsUnicode(f));
else {
else if (TmpWCHAR tw=f) {
hmod = GetModuleHandleW(tw);
} else {
PyErr_SetString(PyExc_TypeError, "servicemanager.__file__ is not a string or unicode !");
goto failed;
}
Expand Down
Loading