mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-06-23 15:30:45 -04:00
Avoiding round-tripping via mbcs on windows in strftime()
This commit is contained in:
parent
1335ca8b54
commit
ae4cd7c902
@ -543,9 +543,9 @@ def strftime(fmt, t=None):
|
|||||||
t[0] = replacement
|
t[0] = replacement
|
||||||
ans = None
|
ans = None
|
||||||
if iswindows:
|
if iswindows:
|
||||||
if isinstance(fmt, unicode):
|
if isinstance(fmt, bytes):
|
||||||
fmt = fmt.encode('mbcs', 'replace')
|
fmt = fmt.decode('mbcs', 'replace')
|
||||||
fmt = fmt.replace(b'%e', b'%#d')
|
fmt = fmt.replace(u'%e', u'%#d')
|
||||||
ans = plugins['winutil'][0].strftime(fmt, t)
|
ans = plugins['winutil'][0].strftime(fmt, t)
|
||||||
else:
|
else:
|
||||||
ans = time.strftime(fmt, t).decode(preferred_encoding, 'replace')
|
ans = time.strftime(fmt, t).decode(preferred_encoding, 'replace')
|
||||||
|
@ -300,84 +300,69 @@ winutil_strftime(PyObject *self, PyObject *args)
|
|||||||
{
|
{
|
||||||
PyObject *tup = NULL;
|
PyObject *tup = NULL;
|
||||||
struct tm buf;
|
struct tm buf;
|
||||||
const char *_fmt;
|
size_t buflen;
|
||||||
size_t fmtlen, buflen;
|
wchar_t *outbuf = NULL;
|
||||||
wchar_t *outbuf = NULL, *fmt = NULL;
|
Py_UNICODE *fmt = NULL;
|
||||||
|
int fmtlen;
|
||||||
size_t i;
|
size_t i;
|
||||||
memset((void *) &buf, '\0', sizeof(buf));
|
memset((void *) &buf, 0, sizeof(buf));
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args, "s|O:strftime", &_fmt, &tup))
|
if (!PyArg_ParseTuple(args, "u#|O:strftime", &fmt, &fmtlen, &tup)) return NULL;
|
||||||
return NULL;
|
|
||||||
|
|
||||||
if (mbstowcs_s(&fmtlen, NULL, 0, _fmt, strlen(_fmt)) != 0) {
|
|
||||||
PyErr_SetString(PyExc_ValueError, "Failed to convert fmt to wchar");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
fmt = (wchar_t *)PyMem_Malloc((fmtlen+2)*sizeof(wchar_t));
|
|
||||||
if (fmt == NULL) return PyErr_NoMemory();
|
|
||||||
if (mbstowcs_s(&fmtlen, fmt, fmtlen+2, _fmt, strlen(_fmt)) != 0) {
|
|
||||||
PyErr_SetString(PyExc_ValueError, "Failed to convert fmt to wchar");
|
|
||||||
goto end;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tup == NULL) {
|
if (tup == NULL) {
|
||||||
time_t tt = time(NULL);
|
time_t tt = time(NULL);
|
||||||
if(localtime_s(&buf, &tt) != 0) {
|
if(localtime_s(&buf, &tt) != 0) {
|
||||||
PyErr_SetString(PyExc_ValueError, "Failed to get localtime()");
|
PyErr_SetString(PyExc_ValueError, "Failed to get localtime()");
|
||||||
goto end;
|
return NULL;
|
||||||
}
|
}
|
||||||
} else if (!gettmarg(tup, &buf))
|
} else if (!gettmarg(tup, &buf)) return NULL;
|
||||||
goto end;
|
|
||||||
|
|
||||||
if (buf.tm_mon == -1)
|
if (buf.tm_mon == -1) buf.tm_mon = 0;
|
||||||
buf.tm_mon = 0;
|
|
||||||
else if (buf.tm_mon < 0 || buf.tm_mon > 11) {
|
else if (buf.tm_mon < 0 || buf.tm_mon > 11) {
|
||||||
PyErr_SetString(PyExc_ValueError, "month out of range");
|
PyErr_SetString(PyExc_ValueError, "month out of range");
|
||||||
goto end;
|
return NULL;
|
||||||
}
|
}
|
||||||
if (buf.tm_mday == 0)
|
if (buf.tm_mday == 0) buf.tm_mday = 1;
|
||||||
buf.tm_mday = 1;
|
|
||||||
else if (buf.tm_mday < 0 || buf.tm_mday > 31) {
|
else if (buf.tm_mday < 0 || buf.tm_mday > 31) {
|
||||||
PyErr_SetString(PyExc_ValueError, "day of month out of range");
|
PyErr_SetString(PyExc_ValueError, "day of month out of range");
|
||||||
goto end;
|
return NULL;
|
||||||
}
|
}
|
||||||
if (buf.tm_hour < 0 || buf.tm_hour > 23) {
|
if (buf.tm_hour < 0 || buf.tm_hour > 23) {
|
||||||
PyErr_SetString(PyExc_ValueError, "hour out of range");
|
PyErr_SetString(PyExc_ValueError, "hour out of range");
|
||||||
goto end;
|
return NULL;
|
||||||
}
|
}
|
||||||
if (buf.tm_min < 0 || buf.tm_min > 59) {
|
if (buf.tm_min < 0 || buf.tm_min > 59) {
|
||||||
PyErr_SetString(PyExc_ValueError, "minute out of range");
|
PyErr_SetString(PyExc_ValueError, "minute out of range");
|
||||||
goto end;
|
return NULL;
|
||||||
}
|
}
|
||||||
if (buf.tm_sec < 0 || buf.tm_sec > 61) {
|
if (buf.tm_sec < 0 || buf.tm_sec > 61) {
|
||||||
PyErr_SetString(PyExc_ValueError, "seconds out of range");
|
PyErr_SetString(PyExc_ValueError, "seconds out of range");
|
||||||
goto end;
|
return NULL;
|
||||||
}
|
}
|
||||||
/* tm_wday does not need checking of its upper-bound since taking
|
/* tm_wday does not need checking of its upper-bound since taking
|
||||||
``% 7`` in gettmarg() automatically restricts the range. */
|
``% 7`` in gettmarg() automatically restricts the range. */
|
||||||
if (buf.tm_wday < 0) {
|
if (buf.tm_wday < 0) {
|
||||||
PyErr_SetString(PyExc_ValueError, "day of week out of range");
|
PyErr_SetString(PyExc_ValueError, "day of week out of range");
|
||||||
goto end;
|
return NULL;
|
||||||
}
|
}
|
||||||
if (buf.tm_yday == -1)
|
if (buf.tm_yday == -1) buf.tm_yday = 0;
|
||||||
buf.tm_yday = 0;
|
|
||||||
else if (buf.tm_yday < 0 || buf.tm_yday > 365) {
|
else if (buf.tm_yday < 0 || buf.tm_yday > 365) {
|
||||||
PyErr_SetString(PyExc_ValueError, "day of year out of range");
|
PyErr_SetString(PyExc_ValueError, "day of year out of range");
|
||||||
goto end;
|
return NULL;
|
||||||
}
|
}
|
||||||
if (buf.tm_isdst < -1 || buf.tm_isdst > 1) {
|
if (buf.tm_isdst < -1 || buf.tm_isdst > 1) {
|
||||||
PyErr_SetString(PyExc_ValueError,
|
PyErr_SetString(PyExc_ValueError,
|
||||||
"daylight savings flag out of range");
|
"daylight savings flag out of range");
|
||||||
goto end;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 5*fmtlen; ; i += i) {
|
for (i = 5*(unsigned int)fmtlen; ; i += i) {
|
||||||
outbuf = (wchar_t *)PyMem_Malloc(i*sizeof(wchar_t));
|
outbuf = (wchar_t *)PyMem_Malloc(i*sizeof(wchar_t));
|
||||||
if (outbuf == NULL) {
|
if (outbuf == NULL) {
|
||||||
PyErr_NoMemory(); goto end;
|
PyErr_NoMemory(); return NULL;
|
||||||
}
|
}
|
||||||
buflen = wcsftime(outbuf, i, fmt, &buf);
|
buflen = wcsftime(outbuf, i, fmt, &buf);
|
||||||
if (buflen > 0 || i >= 256 * fmtlen) {
|
if (buflen > 0 || i >= 256 * (unsigned int)fmtlen) {
|
||||||
/* If the buffer is 256 times as long as the format,
|
/* If the buffer is 256 times as long as the format,
|
||||||
it's probably not failing for lack of room!
|
it's probably not failing for lack of room!
|
||||||
More likely, the format yields an empty result,
|
More likely, the format yields an empty result,
|
||||||
@ -385,20 +370,17 @@ winutil_strftime(PyObject *self, PyObject *args)
|
|||||||
is unknown. */
|
is unknown. */
|
||||||
PyObject *ret;
|
PyObject *ret;
|
||||||
ret = PyUnicode_FromWideChar(outbuf, buflen);
|
ret = PyUnicode_FromWideChar(outbuf, buflen);
|
||||||
PyMem_Free(outbuf); PyMem_Free(fmt);
|
PyMem_Free(outbuf);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
PyMem_Free(outbuf);
|
PyMem_Free(outbuf);
|
||||||
#if defined _MSC_VER && _MSC_VER >= 1400 && defined(__STDC_SECURE_LIB__)
|
|
||||||
/* VisualStudio .NET 2005 does this properly */
|
/* VisualStudio .NET 2005 does this properly */
|
||||||
if (buflen == 0 && errno == EINVAL) {
|
if (buflen == 0 && errno == EINVAL) {
|
||||||
PyErr_SetString(PyExc_ValueError, "Invalid format string");
|
PyErr_SetString(PyExc_ValueError, "Invalid format string");
|
||||||
goto end;
|
return NULL;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
end:
|
return NULL;
|
||||||
PyMem_Free(fmt); return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user