[Bf-blender-cvs] SVN commit: /data/svn/bf-blender [31701] trunk/blender: bugfix [#23285] Exporters not available whel using special characters in path name

Campbell Barton ideasman42 at gmail.com
Wed Sep 1 16:13:49 CEST 2010


Revision: 31701
          http://projects.blender.org/plugins/scmsvn/viewcvs.php?view=rev&root=bf-blender&revision=31701
Author:   campbellbarton
Date:     2010-09-01 16:13:48 +0200 (Wed, 01 Sep 2010)

Log Message:
-----------
bugfix [#23285] Exporters not available whel using special characters in path name
- ID properties now suopport non utf-8 strings for their values but not their keys.
- moved utility functions into py_capi_utils.c from bpy_utils and bpy_rna.
- import/export paths have to be printed with repr() or %r, so non utf-8 chars are escaped.

Modified Paths:
--------------
    trunk/blender/release/scripts/op/io_scene_x3d/export_x3d.py
    trunk/blender/source/blender/python/generic/IDProp.c
    trunk/blender/source/blender/python/intern/bpy_props.c
    trunk/blender/source/blender/python/intern/bpy_rna.c
    trunk/blender/source/blender/python/intern/bpy_util.c
    trunk/blender/source/blender/python/intern/bpy_util.h

Added Paths:
-----------
    trunk/blender/source/blender/python/generic/py_capi_utils.c
    trunk/blender/source/blender/python/generic/py_capi_utils.h

Modified: trunk/blender/release/scripts/op/io_scene_x3d/export_x3d.py
===================================================================
--- trunk/blender/release/scripts/op/io_scene_x3d/export_x3d.py	2010-09-01 13:55:41 UTC (rev 31700)
+++ trunk/blender/release/scripts/op/io_scene_x3d/export_x3d.py	2010-09-01 14:13:48 UTC (rev 31701)
@@ -136,12 +136,12 @@
 
     def writeHeader(self):
         #bfile = sys.expandpath( Blender.Get('filepath') ).replace('<', '&lt').replace('>', '&gt')
-        bfile = self.filepath.replace('<', '&lt').replace('>', '&gt') # use outfile name
+        bfile = repr(os.path.basename(self.filepath).replace('<', '&lt').replace('>', '&gt'))[1:-1] # use outfile name
         self.file.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n")
         self.file.write("<!DOCTYPE X3D PUBLIC \"ISO//Web3D//DTD X3D 3.0//EN\" \"http://www.web3d.org/specifications/x3d-3.0.dtd\">\n")
         self.file.write("<X3D version=\"3.0\" profile=\"Immersive\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema-instance\" xsd:noNamespaceSchemaLocation=\"http://www.web3d.org/specifications/x3d-3.0.xsd\">\n")
         self.file.write("<head>\n")
-        self.file.write("\t<meta name=\"filename\" content=\"%s\" />\n" % os.path.basename(bfile))
+        self.file.write("\t<meta name=\"filename\" content=\"%s\" />\n" % bfile)
         # self.file.write("\t<meta name=\"filename\" content=\"%s\" />\n" % sys.basename(bfile))
         self.file.write("\t<meta name=\"generator\" content=\"Blender %s\" />\n" % bpy.app.version_string)
         # self.file.write("\t<meta name=\"generator\" content=\"Blender %s\" />\n" % Blender.Get('version'))
@@ -781,7 +781,7 @@
             EXPORT_TRI=				False,\
         ):
 
-        print("Info: starting X3D export to " + self.filepath + "...")
+        print("Info: starting X3D export to %r..." % self.filepath)
         self.writeHeader()
         # self.writeScript()
         self.writeNavigationInfo(scene)
@@ -879,7 +879,7 @@
         self.texNames={}
         self.matNames={}
         self.indentLevel=0
-        print("Info: finished X3D export to %s\n" % self.filepath)
+        print("Info: finished X3D export to %r" % self.filepath)
 
     def cleanStr(self, name, prefix='rsvd_'):
         """cleanStr(name,prefix) - try to create a valid VRML DEF name from object name"""

Modified: trunk/blender/source/blender/python/generic/IDProp.c
===================================================================
--- trunk/blender/source/blender/python/generic/IDProp.c	2010-09-01 13:55:41 UTC (rev 31700)
+++ trunk/blender/source/blender/python/generic/IDProp.c	2010-09-01 14:13:48 UTC (rev 31701)
@@ -27,6 +27,15 @@
 #include "IDProp.h"
 #include "MEM_guardedalloc.h"
 
+#define USE_STRING_COERCE
+
+#ifdef USE_STRING_COERCE
+#include "py_capi_utils.h"
+#endif
+
+PyObject *		PyC_UnicodeFromByte(const char *str);
+const char *	PuC_UnicodeAsByte(PyObject *py_str, PyObject **coerce); /* coerce must be NULL */
+
 /*** Function to wrap ID properties ***/
 PyObject *BPy_Wrap_IDProperty(ID *id, IDProperty *prop, IDProperty *parent);
 
@@ -46,7 +55,11 @@
 {
 	switch ( prop->type ) {
 		case IDP_STRING:
-			return PyUnicode_FromString( prop->data.pointer );
+#ifdef USE_STRING_COERCE
+			return PyC_UnicodeFromByte(prop->data.pointer);
+#else
+			return PyUnicode_FromString(prop->data.pointer);
+#endif
 		case IDP_INT:
 			return PyLong_FromLong( (long)prop->data.val );
 		case IDP_FLOAT:
@@ -105,10 +118,25 @@
 				PyErr_SetString(PyExc_TypeError, "expected a string!");
 				return -1;
 			}
+#ifdef USE_STRING_COERCE
+			{
+				int alloc_len;
+				PyObject *value_coerce= NULL;
 
+				st= (char *)PuC_UnicodeAsByte(value, &value_coerce);
+				alloc_len= strlen(st) + 1;
+
+				st = _PyUnicode_AsString(value);
+				IDP_ResizeArray(prop, alloc_len);
+				memcpy(prop->data.pointer, st, alloc_len);
+				Py_XDECREF(value_coerce);
+			}
+#else
 			st = _PyUnicode_AsString(value);
 			IDP_ResizeArray(prop, strlen(st)+1);
 			strcpy(prop->data.pointer, st);
+#endif
+
 			return 0;
 		}
 
@@ -281,8 +309,15 @@
 		val.i = (int) PyLong_AsSsize_t(ob);
 		prop = IDP_New(IDP_INT, val, name);
 	} else if (PyUnicode_Check(ob)) {
+#ifdef USE_STRING_COERCE
+		PyObject *value_coerce= NULL;
+		val.str = (char *)PuC_UnicodeAsByte(ob, &value_coerce);
+		prop = IDP_New(IDP_STRING, val, name);
+		Py_XDECREF(value_coerce);
+#else
 		val.str = _PyUnicode_AsString(ob);
 		prop = IDP_New(IDP_STRING, val, name);
+#endif
 	} else if (PySequence_Check(ob)) {
 		PyObject *item;
 		int i;
@@ -432,7 +467,11 @@
 {
 	switch (prop->type) {
 		case IDP_STRING:
+#ifdef USE_STRING_COERCE
+			return PyC_UnicodeFromByte(prop->data.pointer);
+#else
 			return PyUnicode_FromString(prop->data.pointer);
+#endif
 			break;
 		case IDP_FLOAT:
 			return PyFloat_FromDouble(*((float*)&prop->data.val));

Added: trunk/blender/source/blender/python/generic/py_capi_utils.c
===================================================================
--- trunk/blender/source/blender/python/generic/py_capi_utils.c	                        (rev 0)
+++ trunk/blender/source/blender/python/generic/py_capi_utils.c	2010-09-01 14:13:48 UTC (rev 31701)
@@ -0,0 +1,271 @@
+/* 
+ * $Id:
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+*/
+
+#include <Python.h>
+#include "py_capi_utils.h"
+
+/* for debugging */
+void PyC_ObSpit(char *name, PyObject *var) {
+	fprintf(stderr, "<%s> : ", name);
+	if (var==NULL) {
+		fprintf(stderr, "<NIL>");
+	}
+	else {
+		PyObject_Print(var, stderr, 0);
+		fprintf(stderr, " ref:%d ", (int)var->ob_refcnt);
+		fprintf(stderr, " ptr:%p", (void *)var);
+		
+		fprintf(stderr, " type:");
+		if(Py_TYPE(var))
+			fprintf(stderr, "%s", Py_TYPE(var)->tp_name);
+		else
+			fprintf(stderr, "<NIL>");
+	}
+	fprintf(stderr, "\n");
+}
+
+void PyC_LineSpit(void) {
+	const char *filename;
+	int lineno;
+
+	PyErr_Clear();
+	PyC_FileAndNum(&filename, &lineno);
+	
+	fprintf(stderr, "%s:%d\n", filename, lineno);
+}
+
+void PyC_FileAndNum(const char **filename, int *lineno)
+{
+	PyObject *getframe, *frame;
+	PyObject *f_lineno= NULL, *co_filename= NULL;
+	
+	if (filename)	*filename= NULL;
+	if (lineno)		*lineno = -1;
+	
+	getframe = PySys_GetObject("_getframe"); // borrowed
+	if (getframe==NULL) {
+		PyErr_Clear();
+		return;
+	}
+	
+	frame = PyObject_CallObject(getframe, NULL);
+	if (frame==NULL) {
+		PyErr_Clear();
+		return;
+	}
+	
+	/* when executing a script */
+	if (filename) {
+		co_filename= PyC_Object_GetAttrStringArgs(frame, 1, "f_code", "co_filename");
+		if (co_filename==NULL) {
+			PyErr_SetString(PyExc_SystemError, "Could not access sys._getframe().f_code.co_filename");
+			Py_DECREF(frame);
+			return;
+		}
+		
+		*filename = _PyUnicode_AsString(co_filename);
+		Py_DECREF(co_filename);
+	}
+	
+	/* when executing a module */
+	if(filename && *filename == NULL) {
+		/* try an alternative method to get the filename - module based
+		 * references below are all borrowed (double checked) */
+		PyObject *mod_name= PyDict_GetItemString(PyEval_GetGlobals(), "__name__");
+		if(mod_name) {
+			PyObject *mod= PyDict_GetItem(PyImport_GetModuleDict(), mod_name);
+			if(mod) {
+				*filename= PyModule_GetFilename(mod);
+			}
+
+			/* unlikely, fallback */
+			if(*filename == NULL) {
+				*filename= _PyUnicode_AsString(mod_name);
+			}
+		}
+	}
+		
+	
+	if (lineno) {
+		f_lineno= PyObject_GetAttrString(frame, "f_lineno");
+		if (f_lineno==NULL) {
+			PyErr_SetString(PyExc_SystemError, "Could not access sys._getframe().f_lineno");
+			Py_DECREF(frame);
+			return;
+		}
+		
+		*lineno = (int)PyLong_AsSsize_t(f_lineno);
+		Py_DECREF(f_lineno);
+	}
+
+	Py_DECREF(frame);
+}
+
+/* Would be nice if python had this built in */
+PyObject *PyC_Object_GetAttrStringArgs(PyObject *o, Py_ssize_t n, ...)
+{
+	Py_ssize_t i;
+	PyObject *item= o;
+	char *attr;
+	
+	va_list vargs;
+
+	va_start(vargs, n);
+	for (i=0; i<n; i++) {
+		attr = va_arg(vargs, char *);
+		item = PyObject_GetAttrString(item, attr);
+		
+		if (item) 
+			Py_DECREF(item);
+		else /* python will set the error value here */
+			break;
+		
+	}
+	va_end(vargs);
+	
+	Py_XINCREF(item); /* final value has is increfed, to match PyObject_GetAttrString */
+	return item;
+}
+
+/* returns the exception string as a new PyUnicode object, depends on external StringIO module */
+PyObject *PyC_ExceptionBuffer(void)
+{
+	PyObject *stdout_backup = PySys_GetObject("stdout"); /* borrowed */
+	PyObject *stderr_backup = PySys_GetObject("stderr"); /* borrowed */
+	PyObject *string_io = NULL;
+	PyObject *string_io_buf = NULL;
+	PyObject *string_io_mod= NULL;
+	PyObject *string_io_getvalue= NULL;
+	
+	PyObject *error_type, *error_value, *error_traceback;
+	
+	if (!PyErr_Occurred())
+		return NULL;
+	
+	PyErr_Fetch(&error_type, &error_value, &error_traceback);
+	
+	PyErr_Clear();
+	
+	/* import io
+	 * string_io = io.StringIO()
+	 */
+	
+	if(! (string_io_mod= PyImport_ImportModule("io")) ) {
+		goto error_cleanup;
+	} else if (! (string_io = PyObject_CallMethod(string_io_mod, "StringIO", NULL))) {
+		goto error_cleanup;
+	} else if (! (string_io_getvalue= PyObject_GetAttrString(string_io, "getvalue"))) {
+		goto error_cleanup;
+	}
+	
+	Py_INCREF(stdout_backup); // since these were borrowed we dont want them freed when replaced.
+	Py_INCREF(stderr_backup);
+	
+	PySys_SetObject("stdout", string_io); // both of these are free'd when restoring
+	PySys_SetObject("stderr", string_io);
+	
+	PyErr_Restore(error_type, error_value, error_traceback);
+	PyErr_Print(); /* print the error */
+	PyErr_Clear();
+	
+	string_io_buf = PyObject_CallObject(string_io_getvalue, NULL);
+	
+	PySys_SetObject("stdout", stdout_backup);
+	PySys_SetObject("stderr", stderr_backup);
+	
+	Py_DECREF(stdout_backup); /* now sys owns the ref again */
+	Py_DECREF(stderr_backup);
+	

@@ Diff output truncated at 10240 characters. @@




More information about the Bf-blender-cvs mailing list