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
|
||||
ans = None
|
||||
if iswindows:
|
||||
if isinstance(fmt, unicode):
|
||||
fmt = fmt.encode('mbcs', 'replace')
|
||||
fmt = fmt.replace(b'%e', b'%#d')
|
||||
if isinstance(fmt, bytes):
|
||||
fmt = fmt.decode('mbcs', 'replace')
|
||||
fmt = fmt.replace(u'%e', u'%#d')
|
||||
ans = plugins['winutil'][0].strftime(fmt, t)
|
||||
else:
|
||||
ans = time.strftime(fmt, t).decode(preferred_encoding, 'replace')
|
||||
|
@ -300,84 +300,69 @@ winutil_strftime(PyObject *self, PyObject *args)
|
||||
{
|
||||
PyObject *tup = NULL;
|
||||
struct tm buf;
|
||||
const char *_fmt;
|
||||
size_t fmtlen, buflen;
|
||||
wchar_t *outbuf = NULL, *fmt = NULL;
|
||||
size_t buflen;
|
||||
wchar_t *outbuf = NULL;
|
||||
Py_UNICODE *fmt = NULL;
|
||||
int fmtlen;
|
||||
size_t i;
|
||||
memset((void *) &buf, '\0', sizeof(buf));
|
||||
memset((void *) &buf, 0, sizeof(buf));
|
||||
|
||||
if (!PyArg_ParseTuple(args, "s|O:strftime", &_fmt, &tup))
|
||||
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 (!PyArg_ParseTuple(args, "u#|O:strftime", &fmt, &fmtlen, &tup)) return NULL;
|
||||
|
||||
if (tup == NULL) {
|
||||
time_t tt = time(NULL);
|
||||
if(localtime_s(&buf, &tt) != 0) {
|
||||
PyErr_SetString(PyExc_ValueError, "Failed to get localtime()");
|
||||
goto end;
|
||||
return NULL;
|
||||
}
|
||||
} else if (!gettmarg(tup, &buf))
|
||||
goto end;
|
||||
} else if (!gettmarg(tup, &buf)) return NULL;
|
||||
|
||||
if (buf.tm_mon == -1)
|
||||
buf.tm_mon = 0;
|
||||
if (buf.tm_mon == -1) buf.tm_mon = 0;
|
||||
else if (buf.tm_mon < 0 || buf.tm_mon > 11) {
|
||||
PyErr_SetString(PyExc_ValueError, "month out of range");
|
||||
goto end;
|
||||
}
|
||||
if (buf.tm_mday == 0)
|
||||
buf.tm_mday = 1;
|
||||
PyErr_SetString(PyExc_ValueError, "month out of range");
|
||||
return NULL;
|
||||
}
|
||||
if (buf.tm_mday == 0) buf.tm_mday = 1;
|
||||
else if (buf.tm_mday < 0 || buf.tm_mday > 31) {
|
||||
PyErr_SetString(PyExc_ValueError, "day of month out of range");
|
||||
goto end;
|
||||
}
|
||||
if (buf.tm_hour < 0 || buf.tm_hour > 23) {
|
||||
PyErr_SetString(PyExc_ValueError, "hour out of range");
|
||||
goto end;
|
||||
}
|
||||
if (buf.tm_min < 0 || buf.tm_min > 59) {
|
||||
PyErr_SetString(PyExc_ValueError, "minute out of range");
|
||||
goto end;
|
||||
}
|
||||
if (buf.tm_sec < 0 || buf.tm_sec > 61) {
|
||||
PyErr_SetString(PyExc_ValueError, "seconds out of range");
|
||||
goto end;
|
||||
}
|
||||
/* tm_wday does not need checking of its upper-bound since taking
|
||||
``% 7`` in gettmarg() automatically restricts the range. */
|
||||
if (buf.tm_wday < 0) {
|
||||
PyErr_SetString(PyExc_ValueError, "day of week out of range");
|
||||
goto end;
|
||||
}
|
||||
if (buf.tm_yday == -1)
|
||||
buf.tm_yday = 0;
|
||||
PyErr_SetString(PyExc_ValueError, "day of month out of range");
|
||||
return NULL;
|
||||
}
|
||||
if (buf.tm_hour < 0 || buf.tm_hour > 23) {
|
||||
PyErr_SetString(PyExc_ValueError, "hour out of range");
|
||||
return NULL;
|
||||
}
|
||||
if (buf.tm_min < 0 || buf.tm_min > 59) {
|
||||
PyErr_SetString(PyExc_ValueError, "minute out of range");
|
||||
return NULL;
|
||||
}
|
||||
if (buf.tm_sec < 0 || buf.tm_sec > 61) {
|
||||
PyErr_SetString(PyExc_ValueError, "seconds out of range");
|
||||
return NULL;
|
||||
}
|
||||
/* tm_wday does not need checking of its upper-bound since taking
|
||||
``% 7`` in gettmarg() automatically restricts the range. */
|
||||
if (buf.tm_wday < 0) {
|
||||
PyErr_SetString(PyExc_ValueError, "day of week out of range");
|
||||
return NULL;
|
||||
}
|
||||
if (buf.tm_yday == -1) buf.tm_yday = 0;
|
||||
else if (buf.tm_yday < 0 || buf.tm_yday > 365) {
|
||||
PyErr_SetString(PyExc_ValueError, "day of year out of range");
|
||||
goto end;
|
||||
}
|
||||
if (buf.tm_isdst < -1 || buf.tm_isdst > 1) {
|
||||
PyErr_SetString(PyExc_ValueError,
|
||||
"daylight savings flag out of range");
|
||||
goto end;
|
||||
}
|
||||
PyErr_SetString(PyExc_ValueError, "day of year out of range");
|
||||
return NULL;
|
||||
}
|
||||
if (buf.tm_isdst < -1 || buf.tm_isdst > 1) {
|
||||
PyErr_SetString(PyExc_ValueError,
|
||||
"daylight savings flag out of range");
|
||||
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));
|
||||
if (outbuf == NULL) {
|
||||
PyErr_NoMemory(); goto end;
|
||||
PyErr_NoMemory(); return NULL;
|
||||
}
|
||||
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,
|
||||
it's probably not failing for lack of room!
|
||||
More likely, the format yields an empty result,
|
||||
@ -385,20 +370,17 @@ winutil_strftime(PyObject *self, PyObject *args)
|
||||
is unknown. */
|
||||
PyObject *ret;
|
||||
ret = PyUnicode_FromWideChar(outbuf, buflen);
|
||||
PyMem_Free(outbuf); PyMem_Free(fmt);
|
||||
PyMem_Free(outbuf);
|
||||
return ret;
|
||||
}
|
||||
PyMem_Free(outbuf);
|
||||
#if defined _MSC_VER && _MSC_VER >= 1400 && defined(__STDC_SECURE_LIB__)
|
||||
/* VisualStudio .NET 2005 does this properly */
|
||||
if (buflen == 0 && errno == EINVAL) {
|
||||
PyErr_SetString(PyExc_ValueError, "Invalid format string");
|
||||
goto end;
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
end:
|
||||
PyMem_Free(fmt); return NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user