From 2ab17326135e666dd31bb0695ebc2ef426615fae Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Tue, 15 Nov 2011 09:12:10 +0000 Subject: support for non-null terminated byte strings in id properties (as a subtype of IDP_STRING types) --- source/blender/blenkernel/BKE_idprop.h | 6 +++- source/blender/blenkernel/intern/idprop.c | 55 ++++++++++++++++++++--------- source/blender/makesdna/DNA_ID.h | 7 ++++ source/blender/makesrna/intern/rna_access.c | 30 ++++++++++++---- source/blender/python/generic/IDProp.c | 32 ++++++++++++++--- 5 files changed, 101 insertions(+), 29 deletions(-) diff --git a/source/blender/blenkernel/BKE_idprop.h b/source/blender/blenkernel/BKE_idprop.h index 10c02f54b2e..ef760277f56 100644 --- a/source/blender/blenkernel/BKE_idprop.h +++ b/source/blender/blenkernel/BKE_idprop.h @@ -40,7 +40,11 @@ typedef union IDPropertyTemplate { int i; float f; double d; - char *str; + struct { + char *str; + short len; + char subtype; + } string; struct ID *id; struct { short type; diff --git a/source/blender/blenkernel/intern/idprop.c b/source/blender/blenkernel/intern/idprop.c index ac4b936cb41..07057e4ee32 100644 --- a/source/blender/blenkernel/intern/idprop.c +++ b/source/blender/blenkernel/intern/idprop.c @@ -349,17 +349,20 @@ static IDProperty *IDP_CopyString(IDProperty *prop) void IDP_AssignString(IDProperty *prop, const char *st, int maxlen) { - int stlen; - - stlen = strlen(st); + int stlen = strlen(st); if(maxlen > 0 && maxlen < stlen) stlen= maxlen; - stlen++; /* make room for null byte */ - - IDP_ResizeArray(prop, stlen); - BLI_strncpy(prop->data.pointer, st, stlen); + if (prop->subtype == IDP_STRING_SUB_BYTE) { + IDP_ResizeArray(prop, stlen); + memcpy(prop->data.pointer, st, stlen); + } + else { + stlen++; /* make room for null byte */ + IDP_ResizeArray(prop, stlen); + BLI_strncpy(prop->data.pointer, st, stlen); + } } void IDP_ConcatStringC(IDProperty *prop, const char *st) @@ -703,18 +706,36 @@ IDProperty *IDP_New(int type, IDPropertyTemplate val, const char *name) } case IDP_STRING: { - char *st = val.str; + const char *st = val.string.str; prop = MEM_callocN(sizeof(IDProperty), "IDProperty string"); - if (st == NULL) { - prop->data.pointer = MEM_callocN(DEFAULT_ALLOC_FOR_NULL_STRINGS, "id property string 1"); - prop->totallen = DEFAULT_ALLOC_FOR_NULL_STRINGS; - prop->len = 1; /*NULL string, has len of 1 to account for null byte.*/ - } else { - int stlen = strlen(st) + 1; - prop->data.pointer = MEM_mallocN(stlen, "id property string 2"); - prop->len = prop->totallen = stlen; - memcpy(prop->data.pointer, st, stlen); + if (val.string.subtype == IDP_STRING_SUB_BYTE) { + /* note, intentionally not null terminated */ + if (st == NULL) { + prop->data.pointer = MEM_callocN(DEFAULT_ALLOC_FOR_NULL_STRINGS, "id property string 1"); + prop->totallen = DEFAULT_ALLOC_FOR_NULL_STRINGS; + prop->len = 0; + } + else { + prop->data.pointer = MEM_mallocN(val.string.len, "id property string 2"); + prop->len = prop->totallen = val.string.len; + memcpy(prop->data.pointer, st, val.string.len); + } + prop->subtype= IDP_STRING_SUB_BYTE; + } + else { + if (st == NULL) { + prop->data.pointer = MEM_callocN(DEFAULT_ALLOC_FOR_NULL_STRINGS, "id property string 1"); + prop->totallen = DEFAULT_ALLOC_FOR_NULL_STRINGS; + prop->len = 1; /*NULL string, has len of 1 to account for null byte.*/ + } + else { + int stlen = strlen(st) + 1; + prop->data.pointer = MEM_mallocN(stlen, "id property string 3"); + prop->len = prop->totallen = stlen; + memcpy(prop->data.pointer, st, stlen); + } + prop->subtype= IDP_STRING_SUB_UTF8; } break; } diff --git a/source/blender/makesdna/DNA_ID.h b/source/blender/makesdna/DNA_ID.h index c135254b11b..97ea7592d04 100644 --- a/source/blender/makesdna/DNA_ID.h +++ b/source/blender/makesdna/DNA_ID.h @@ -80,6 +80,13 @@ typedef struct IDProperty { #define IDP_IDPARRAY 9 #define IDP_NUMTYPES 10 +/*->subtype */ + +/* IDP_STRING */ +#define IDP_STRING_SUB_UTF8 0 /* default */ +#define IDP_STRING_SUB_BYTE 1 /* arbitrary byte array, _not_ null terminated */ + + /* add any future new id property types here.*/ /* watch it: Sequence has identical beginning. */ diff --git a/source/blender/makesrna/intern/rna_access.c b/source/blender/makesrna/intern/rna_access.c index 6f9c7a8f19b..47a7420cb7f 100644 --- a/source/blender/makesrna/intern/rna_access.c +++ b/source/blender/makesrna/intern/rna_access.c @@ -2271,12 +2271,23 @@ void RNA_property_string_get(PointerRNA *ptr, PropertyRNA *prop, char *value) BLI_assert(RNA_property_type(prop) == PROP_STRING); - if((idprop=rna_idproperty_check(&prop, ptr))) - strcpy(value, IDP_String(idprop)); - else if(sprop->get) + if((idprop=rna_idproperty_check(&prop, ptr))) { + /* editing bytes is not 100% supported + * since they can contain NIL chars */ + if (idprop->subtype == IDP_STRING_SUB_BYTE) { + memcpy(value, IDP_String(idprop), idprop->len + 1); + value[idprop->len]= '\0'; + } + else { + strcpy(value, IDP_String(idprop)); + } + } + else if(sprop->get) { sprop->get(ptr, value); - else + } + else { strcpy(value, sprop->defaultvalue); + } } char *RNA_property_string_get_alloc(PointerRNA *ptr, PropertyRNA *prop, @@ -2320,8 +2331,14 @@ int RNA_property_string_length(PointerRNA *ptr, PropertyRNA *prop) BLI_assert(RNA_property_type(prop) == PROP_STRING); - if((idprop=rna_idproperty_check(&prop, ptr))) - return strlen(IDP_String(idprop)); + if((idprop=rna_idproperty_check(&prop, ptr))) { + if (idprop->subtype == IDP_STRING_SUB_BYTE) { + return idprop->len; + } + else { + return strlen(IDP_String(idprop)); + } + } else if(sprop->length) return sprop->length(ptr); else @@ -2336,6 +2353,7 @@ void RNA_property_string_set(PointerRNA *ptr, PropertyRNA *prop, const char *val BLI_assert(RNA_property_type(prop) == PROP_STRING); if((idprop=rna_idproperty_check(&prop, ptr))) + /* both IDP_STRING_SUB_BYTE / IDP_STRING_SUB_UTF8 */ IDP_AssignString(idprop, value, RNA_property_string_maxlength(prop) - 1); else if(sprop->set) sprop->set(ptr, value); /* set function needs to clamp its self */ diff --git a/source/blender/python/generic/IDProp.c b/source/blender/python/generic/IDProp.c index 6d869a7eb1f..d0759a69d8f 100644 --- a/source/blender/python/generic/IDProp.c +++ b/source/blender/python/generic/IDProp.c @@ -64,11 +64,18 @@ PyObject *BPy_IDGroup_WrapData( ID *id, IDProperty *prop ) { switch ( prop->type ) { case IDP_STRING: + + if (prop->subtype == IDP_STRING_SUB_BYTE) { + return PyBytes_FromStringAndSize(IDP_Array(prop), prop->len); + } + else { #ifdef USE_STRING_COERCE - return PyC_UnicodeFromByteAndSize(IDP_Array(prop), prop->len - 1); + return PyC_UnicodeFromByteAndSize(IDP_Array(prop), prop->len - 1); #else - return PyUnicode_FromStringAndSize(IDP_Array(prop), prop->len - 1); + return PyUnicode_FromStringAndSize(IDP_Array(prop), prop->len - 1); #endif + } + case IDP_INT: return PyLong_FromLong( (long)prop->data.val ); case IDP_FLOAT: @@ -332,7 +339,8 @@ const char *BPy_IDProperty_Map_ValidateAndCreate(PyObject *name_obj, IDProperty else if (PyUnicode_Check(ob)) { #ifdef USE_STRING_COERCE PyObject *value_coerce= NULL; - val.str = (char *)PyC_UnicodeAsByte(ob, &value_coerce); + val.string.str = (char *)PyC_UnicodeAsByte(ob, &value_coerce); + val.string.subtype = IDP_STRING_SUB_UTF8; prop = IDP_New(IDP_STRING, val, name); Py_XDECREF(value_coerce); #else @@ -340,6 +348,15 @@ const char *BPy_IDProperty_Map_ValidateAndCreate(PyObject *name_obj, IDProperty prop = IDP_New(IDP_STRING, val, name); #endif } + else if (PyBytes_Check(ob)) { + val.string.str= PyBytes_AS_STRING(ob); + val.string.len= PyBytes_GET_SIZE(ob); + val.string.subtype= IDP_STRING_SUB_BYTE; + + prop = IDP_New(IDP_STRING, val, name); + //prop = IDP_NewString(PyBytes_AS_STRING(ob), name, PyBytes_GET_SIZE(ob)); + //prop->subtype= IDP_STRING_SUB_BYTE; + } else if (PySequence_Check(ob)) { PyObject *item; int i; @@ -493,11 +510,16 @@ static PyObject *BPy_IDGroup_MapDataToPy(IDProperty *prop) { switch (prop->type) { case IDP_STRING: + if (prop->subtype == IDP_STRING_SUB_BYTE) { + return PyBytes_FromStringAndSize(IDP_Array(prop), prop->len); + } + else { #ifdef USE_STRING_COERCE - return PyC_UnicodeFromByteAndSize(IDP_Array(prop), prop->len - 1); + return PyC_UnicodeFromByteAndSize(IDP_Array(prop), prop->len - 1); #else - return PyUnicode_FromStringAndSize(IDP_Array(prop), prop->len - 1); + return PyUnicode_FromStringAndSize(IDP_Array(prop), prop->len - 1); #endif + } break; case IDP_FLOAT: return PyFloat_FromDouble(*((float*)&prop->data.val)); -- cgit v1.2.3