python/utf8 compatibility fixes. (as discussed on the mailing list)
- user input gets non utf8 chars stripped all text input other then file paths. - python has the same limitations, it will raise an error on non utf8 strings except for paths use unicode escape literals so its possible to deal with saving to these file paths from python. - new string functions BLI_utf8_invalid_byte(str, len) returns the first invalid utf8 byte or -1 on on success. BLI_utf8_invalid_strip(str, len) strips non utf-8 chars.
This commit is contained in:
@@ -49,6 +49,7 @@
|
||||
#include "ED_keyframing.h"
|
||||
|
||||
#define USE_MATHUTILS
|
||||
#define USE_STRING_COERCE
|
||||
|
||||
#ifdef USE_MATHUTILS
|
||||
#include "../generic/mathutils.h" /* so we can have mathutils callbacks */
|
||||
@@ -192,6 +193,62 @@ Mathutils_Callback mathutils_rna_matrix_cb = {
|
||||
NULL
|
||||
};
|
||||
|
||||
#ifdef USE_STRING_COERCE
|
||||
/* string conversion, escape non-unicode chars, coerce must be set to NULL */
|
||||
static const char *py_safe_unicode_to_byte(PyObject *py_str, PyObject **coerce)
|
||||
{
|
||||
char *result;
|
||||
|
||||
result= _PyUnicode_AsString(py_str);
|
||||
|
||||
if(result) {
|
||||
/* 99% of the time this is enough but we better support non unicode
|
||||
* chars since blender doesnt limit this */
|
||||
return result;
|
||||
}
|
||||
else {
|
||||
/* mostly copied from fileio.c's, fileio_init */
|
||||
PyObject *stringobj;
|
||||
PyObject *u;
|
||||
|
||||
PyErr_Clear();
|
||||
|
||||
u= PyUnicode_FromObject(py_str); /* coerce into unicode */
|
||||
|
||||
if (u == NULL)
|
||||
return NULL;
|
||||
|
||||
stringobj= PyUnicode_EncodeUTF8(PyUnicode_AS_UNICODE(u), PyUnicode_GET_SIZE(u), "surrogateescape");
|
||||
Py_DECREF(u);
|
||||
if (stringobj == NULL)
|
||||
return NULL;
|
||||
if (!PyBytes_Check(stringobj)) { /* this seems wrong but it works fine */
|
||||
// printf("encoder failed to return bytes\n");
|
||||
Py_DECREF(stringobj);
|
||||
return NULL;
|
||||
}
|
||||
*coerce= stringobj;
|
||||
|
||||
return PyBytes_AS_STRING(stringobj);
|
||||
}
|
||||
}
|
||||
|
||||
static PyObject *py_safe_byte_to_unicode(char *str)
|
||||
{
|
||||
PyObject *result= PyUnicode_FromString(str);
|
||||
if(result) {
|
||||
/* 99% of the time this is enough but we better support non unicode
|
||||
* chars since blender doesnt limit this */
|
||||
return result;
|
||||
}
|
||||
else {
|
||||
PyErr_Clear();
|
||||
result= PyUnicode_DecodeUTF8(str, strlen(str), "surrogateescape");
|
||||
return result;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* same as RNA_enum_value_from_id but raises an exception */
|
||||
int pyrna_enum_value_from_id(EnumPropertyItem *item, const char *identifier, int *value, const char *error_prefix)
|
||||
{
|
||||
@@ -768,9 +825,20 @@ PyObject * pyrna_prop_to_py(PointerRNA *ptr, PropertyRNA *prop)
|
||||
break;
|
||||
case PROP_STRING:
|
||||
{
|
||||
int subtype= RNA_property_subtype(prop);
|
||||
char *buf;
|
||||
buf = RNA_property_string_get_alloc(ptr, prop, NULL, -1);
|
||||
ret = PyUnicode_FromString( buf );
|
||||
#ifdef USE_STRING_COERCE
|
||||
/* only file paths get special treatment, they may contain non utf-8 chars */
|
||||
if(ELEM3(subtype, PROP_FILEPATH, PROP_DIRPATH, PROP_FILENAME)) {
|
||||
ret= py_safe_byte_to_unicode(buf);
|
||||
}
|
||||
else {
|
||||
ret= PyUnicode_FromString(buf);
|
||||
}
|
||||
#else
|
||||
ret= PyUnicode_FromString(buf);
|
||||
#endif
|
||||
MEM_freeN(buf);
|
||||
break;
|
||||
}
|
||||
@@ -971,16 +1039,31 @@ int pyrna_py_to_prop(PointerRNA *ptr, PropertyRNA *prop, ParameterList *parms, v
|
||||
}
|
||||
case PROP_STRING:
|
||||
{
|
||||
char *param = _PyUnicode_AsString(value);
|
||||
const char *param;
|
||||
#ifdef USE_STRING_COERCE
|
||||
PyObject *value_coerce= NULL;
|
||||
int subtype= RNA_property_subtype(prop);
|
||||
if(ELEM3(subtype, PROP_FILEPATH, PROP_DIRPATH, PROP_FILENAME)) {
|
||||
param= py_safe_unicode_to_byte(value, &value_coerce);
|
||||
}
|
||||
else {
|
||||
param= _PyUnicode_AsString(value);
|
||||
}
|
||||
#else
|
||||
param= _PyUnicode_AsString(value);
|
||||
#endif
|
||||
|
||||
if (param==NULL) {
|
||||
PyErr_Format(PyExc_TypeError, "%.200s %.200s.%.200s expected a string type", error_prefix, RNA_struct_identifier(ptr->type), RNA_property_identifier(prop));
|
||||
return -1;
|
||||
}
|
||||
else {
|
||||
if(data) *((char**)data)= param;
|
||||
if(data) *((char**)data)= param; /*XXX, this assignes a pointer, wouldnt it be better to copy??? */
|
||||
else RNA_property_string_set(ptr, prop, param);
|
||||
}
|
||||
#ifdef USE_STRING_COERCE
|
||||
Py_XDECREF(value_coerce);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
case PROP_ENUM:
|
||||
@@ -1307,7 +1390,7 @@ static PyObject *pyrna_prop_array_subscript_int(BPy_PropertyRNA *self, int keynu
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static PyObject *pyrna_prop_collection_subscript_str(BPy_PropertyRNA *self, char *keyname)
|
||||
static PyObject *pyrna_prop_collection_subscript_str(BPy_PropertyRNA *self, const char *keyname)
|
||||
{
|
||||
PointerRNA newptr;
|
||||
if(RNA_property_collection_lookup_string(&self->ptr, self->prop, keyname, &newptr))
|
||||
@@ -3372,10 +3455,30 @@ PyObject *pyrna_param_to_py(PointerRNA *ptr, ParameterList *parms, PropertyRNA *
|
||||
break;
|
||||
case PROP_STRING:
|
||||
{
|
||||
if(flag & PROP_THICK_WRAP)
|
||||
ret = PyUnicode_FromString( (char*)data );
|
||||
char *data_ch;
|
||||
PyObject *value_coerce= NULL;
|
||||
int subtype= RNA_property_subtype(prop);
|
||||
|
||||
if (flag & PROP_THICK_WRAP)
|
||||
data_ch= (char *)data;
|
||||
else
|
||||
ret = PyUnicode_FromString( *(char**)data );
|
||||
data_ch= *(char **)data;
|
||||
|
||||
#ifdef USE_STRING_COERCE
|
||||
if(ELEM3(subtype, PROP_FILEPATH, PROP_DIRPATH, PROP_FILENAME)) {
|
||||
ret= py_safe_byte_to_unicode(data_ch);
|
||||
}
|
||||
else {
|
||||
ret= PyUnicode_FromString(data_ch);
|
||||
}
|
||||
#else
|
||||
ret = PyUnicode_FromString(data_ch);
|
||||
#endif
|
||||
|
||||
#ifdef USE_STRING_COERCE
|
||||
Py_XDECREF(value_coerce);
|
||||
#endif
|
||||
|
||||
break;
|
||||
}
|
||||
case PROP_ENUM:
|
||||
|
||||
Reference in New Issue
Block a user