From 5c23537daa5c669b672528b0ed2bcaef2038f766 Mon Sep 17 00:00:00 2001 From: Mitchell Stokes Date: Sat, 28 Aug 2010 02:07:55 +0000 Subject: [PATCH] Committing patch [#23278] (by me) This patch allows a user to pass binary data to LibLoad() to load a blend file from memory instead of a file path. I don't know how useful this will be for others, but I've used it so far for: * Decrypting .blend files and loading them without having to store the .blend on the hard drive * Pulling .blend data out of an archive and loading it (again skipping the hard drive) So, it seems the biggest use for this is skipping a bit of file IO (and possibly some security problems). Example usage: import bge with f as open('myfile.blend', 'rb'): data = f.read() bge.logic.LibLoad('Name', 'Scene', data) --- source/blender/blenloader/BLO_readfile.h | 13 ++++++++++++ .../blender/blenloader/intern/readblenentry.c | 9 ++++++++ .../Converter/KX_BlenderSceneConverter.cpp | 20 +++++++++++++++--- .../Converter/KX_BlenderSceneConverter.h | 4 +++- source/gameengine/Ketsji/KX_PythonInit.cpp | 21 ++++++++++++++++--- source/gameengine/PyDoc/bge.logic.rst | 6 ++++-- 6 files changed, 64 insertions(+), 9 deletions(-) diff --git a/source/blender/blenloader/BLO_readfile.h b/source/blender/blenloader/BLO_readfile.h index eeced13b57b..719a3c065ae 100644 --- a/source/blender/blenloader/BLO_readfile.h +++ b/source/blender/blenloader/BLO_readfile.h @@ -122,6 +122,19 @@ BLO_blendfiledata_free( BLO_blendhandle_from_file( char *file); +/** + * Open a blendhandle from memory. + * + * @param mem The data to load from. + * @param memsize The size of the data. + * @return A handle on success, or NULL on failure. + */ + + BlendHandle* +BLO_blendhandle_from_memory( + void *mem, + int memsize); + /** * Gets the names of all the datablocks in a file * of a certain type (ie. All the scene names in diff --git a/source/blender/blenloader/intern/readblenentry.c b/source/blender/blenloader/intern/readblenentry.c index d66d802c8ee..da441214b37 100644 --- a/source/blender/blenloader/intern/readblenentry.c +++ b/source/blender/blenloader/intern/readblenentry.c @@ -76,6 +76,15 @@ BlendHandle *BLO_blendhandle_from_file(char *file) return bh; } +BlendHandle *BLO_blendhandle_from_memory(void *mem, int memsize) +{ + BlendHandle *bh; + + bh= (BlendHandle*)blo_openblendermemory(mem, memsize, NULL); + + return bh; +} + void BLO_blendhandle_print_sizes(BlendHandle *bh, void *fp) { FileData *fd= (FileData*) bh; diff --git a/source/gameengine/Converter/KX_BlenderSceneConverter.cpp b/source/gameengine/Converter/KX_BlenderSceneConverter.cpp index b4ddc4f9e54..1ce6876dda1 100644 --- a/source/gameengine/Converter/KX_BlenderSceneConverter.cpp +++ b/source/gameengine/Converter/KX_BlenderSceneConverter.cpp @@ -932,13 +932,28 @@ Main* KX_BlenderSceneConverter::GetMainDynamicPath(const char *path) return NULL; } -bool KX_BlenderSceneConverter::LinkBlendFile(const char *path, char *group, KX_Scene *scene_merge, char **err_str) +bool KX_BlenderSceneConverter::LinkBlendFileMemory(void *data, int length, const char *path, char *group, KX_Scene *scene_merge, char **err_str) +{ + BlendHandle *bpy_openlib = BLO_blendhandle_from_memory(data, length); + + // Error checking is done in LinkBlendFile + return LinkBlendFile(bpy_openlib, path, group, scene_merge, err_str); +} + +bool KX_BlenderSceneConverter::LinkBlendFilePath(const char *path, char *group, KX_Scene *scene_merge, char **err_str) +{ + BlendHandle *bpy_openlib = BLO_blendhandle_from_file( (char *)path ); + + // Error checking is done in LinkBlendFile + return LinkBlendFile(bpy_openlib, path, group, scene_merge, err_str); +} + +bool KX_BlenderSceneConverter::LinkBlendFile(BlendHandle *bpy_openlib, const char *path, char *group, KX_Scene *scene_merge, char **err_str) { bContext *C; Main *main_newlib; /* stored as a dynamic 'main' until we free it */ Main *main_tmp= NULL; /* created only for linking, then freed */ LinkNode *names = NULL; - BlendHandle *bpy_openlib = NULL; /* ptr to the open .blend file */ int idcode= BKE_idcode_from_name(group); short flag= 0; /* dont need any special options */ ReportList reports; @@ -956,7 +971,6 @@ bool KX_BlenderSceneConverter::LinkBlendFile(const char *path, char *group, KX_S return false; } - bpy_openlib = BLO_blendhandle_from_file( (char *)path ); if(bpy_openlib==NULL) { snprintf(err_local, sizeof(err_local), "could not open blendfile \"%s\"\n", path); *err_str= err_local; diff --git a/source/gameengine/Converter/KX_BlenderSceneConverter.h b/source/gameengine/Converter/KX_BlenderSceneConverter.h index 23d506c98ff..20f3f863563 100644 --- a/source/gameengine/Converter/KX_BlenderSceneConverter.h +++ b/source/gameengine/Converter/KX_BlenderSceneConverter.h @@ -142,7 +142,9 @@ public: struct Main* GetMainDynamicPath(const char *path); vector &GetMainDynamic(); - bool LinkBlendFile(const char *path, char *group, KX_Scene *scene_merge, char **err_str); + bool LinkBlendFileMemory(void *data, int length, const char *path, char *group, KX_Scene *scene_merge, char **err_str); + bool LinkBlendFilePath(const char *path, char *group, KX_Scene *scene_merge, char **err_str); + bool LinkBlendFile(struct BlendHandle *bpy_openlib, const char *path, char *group, KX_Scene *scene_merge, char **err_str); bool MergeScene(KX_Scene *to, KX_Scene *from); RAS_MeshObject *ConvertMeshSpecial(KX_Scene* kx_scene, Main *maggie, const char *name); bool FreeBlendFile(struct Main *maggie); diff --git a/source/gameengine/Ketsji/KX_PythonInit.cpp b/source/gameengine/Ketsji/KX_PythonInit.cpp index 3785f715803..00995fffe73 100644 --- a/source/gameengine/Ketsji/KX_PythonInit.cpp +++ b/source/gameengine/Ketsji/KX_PythonInit.cpp @@ -626,13 +626,28 @@ static PyObject *gLibLoad(PyObject*, PyObject* args) KX_Scene *kx_scene= gp_KetsjiScene; char *path; char *group; + Py_buffer py_buffer; + py_buffer.buf = NULL; char *err_str= NULL; - if (!PyArg_ParseTuple(args,"ss:LibLoad",&path, &group)) + if (!PyArg_ParseTuple(args,"ss|y*:LibLoad",&path, &group, &py_buffer)) return NULL; - if(kx_scene->GetSceneConverter()->LinkBlendFile(path, group, kx_scene, &err_str)) { - Py_RETURN_TRUE; + if (!py_buffer.buf) + { + if(kx_scene->GetSceneConverter()->LinkBlendFilePath(path, group, kx_scene, &err_str)) { + Py_RETURN_TRUE; + } + } + else + { + + if(kx_scene->GetSceneConverter()->LinkBlendFileMemory(py_buffer.buf, py_buffer.len, path, group, kx_scene, &err_str)) { + PyBuffer_Release(&py_buffer); + Py_RETURN_TRUE; + } + + PyBuffer_Release(&py_buffer); } if(err_str) { diff --git a/source/gameengine/PyDoc/bge.logic.rst b/source/gameengine/PyDoc/bge.logic.rst index a10733569f3..a7eb5635d0f 100644 --- a/source/gameengine/PyDoc/bge.logic.rst +++ b/source/gameengine/PyDoc/bge.logic.rst @@ -173,14 +173,16 @@ General functions Restarts the current game by reloading the .blend file (the last saved version, not what is currently running). -.. function:: LibLoad(blend, type) +.. function:: LibLoad(blend, type, data) Converts the all of the datablocks of the given type from the given blend. - :arg blend: The path to the blend file + :arg blend: The path to the blend file (or the name to use for the library if data is supplied) :type blend: string :arg type: The datablock type (currently only "Scene" and "Mesh" are supported) :type type: string + :arg data: Binary data from a blend file (optional) + :type data: bytes .. function:: LibNew(name, type, data)