23extern struct Dtool_PyTypedObject Dtool_BamCacheRecord;
24extern struct Dtool_PyTypedObject Dtool_Filename;
25extern struct Dtool_PyTypedObject Dtool_LoaderOptions;
26extern struct Dtool_PyTypedObject Dtool_PandaNode;
27extern struct Dtool_PyTypedObject Dtool_PythonLoaderFileType;
35PythonLoaderFileType() {
44PythonLoaderFileType(std::string extension, PyObject *entry_point) :
45 _extension(
std::move(extension)),
46 _entry_point(entry_point) {
49 Py_INCREF(entry_point);
56~PythonLoaderFileType() {
57 if (_entry_point !=
nullptr || _load_func !=
nullptr || _save_func !=
nullptr) {
58#if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS)
59 PyGILState_STATE gstate;
60 gstate = PyGILState_Ensure();
63 Py_CLEAR(_entry_point);
67#if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS)
68 PyGILState_Release(gstate);
76bool PythonLoaderFileType::
77init(PyObject *loader) {
78 nassertr(loader !=
nullptr,
false);
79 nassertr(_load_func ==
nullptr,
false);
80 nassertr(_save_func ==
nullptr,
false);
84 PyObject *extensions = PyObject_GetAttrString(loader,
"extensions");
85 if (extensions !=
nullptr) {
86 if (PyUnicode_Check(extensions)
87#
if PY_MAJOR_VERSION < 3
88 || PyString_Check(extensions)
91 Dtool_Raise_TypeError(
"extensions list should be a list or tuple");
92 Py_DECREF(extensions);
96 PyObject *sequence = PySequence_Fast(extensions,
"extensions must be a sequence");
97 PyObject **items = PySequence_Fast_ITEMS(sequence);
98 Py_ssize_t num_items = PySequence_Fast_GET_SIZE(sequence);
99 Py_DECREF(extensions);
101 if (num_items == 0) {
102 PyErr_SetString(PyExc_ValueError,
"extensions list may not be empty");
107 bool found_extension =
false;
109 for (Py_ssize_t i = 0; i < num_items; ++i) {
110 PyObject *extension = items[i];
111 const char *extension_str;
112 Py_ssize_t extension_len;
113 #if PY_MAJOR_VERSION >= 3
114 extension_str = PyUnicode_AsUTF8AndSize(extension, &extension_len);
116 if (PyString_AsStringAndSize(extension, (
char **)&extension_str, &extension_len) == -1) {
117 extension_str =
nullptr;
121 if (extension_str ==
nullptr) {
126 if (_extension.empty()) {
127 _extension.assign(extension_str, extension_len);
128 found_extension =
true;
130 std::string new_extension(extension_str, extension_len);
131 if (_extension == new_extension) {
132 found_extension =
true;
134 if (!_additional_extensions.empty()) {
135 _additional_extensions +=
' ';
137 _additional_extensions += new_extension;
143 if (!found_extension) {
144 PyObject *repr = PyObject_Repr(loader);
146 <<
"Registered extension '" << _extension
147 <<
"' does not occur in extensions list of "
148#if PY_MAJOR_VERSION >= 3
149 << PyUnicode_AsUTF8(repr) <<
"\n";
151 << PyString_AsString(repr) <<
"\n";
160 PyObject *supports_compressed = PyObject_GetAttrString(loader,
"supports_compressed");
161 if (supports_compressed !=
nullptr) {
162 if (supports_compressed == Py_True) {
163 _supports_compressed =
true;
165 else if (supports_compressed == Py_False) {
166 _supports_compressed =
false;
169 Dtool_Raise_TypeError(
"supports_compressed must be a bool");
170 Py_DECREF(supports_compressed);
173 Py_DECREF(supports_compressed);
179 _load_func = PyObject_GetAttrString(loader,
"load_file");
181 _save_func = PyObject_GetAttrString(loader,
"save_file");
184 if (_load_func ==
nullptr && _save_func ==
nullptr) {
185#if PY_MAJOR_VERSION >= 3
186 PyErr_Format(PyExc_TypeError,
187 "loader plug-in %R does not define load_file or save_file function",
190 PyObject *repr = PyObject_Repr(loader);
191 PyErr_Format(PyExc_TypeError,
192 "loader plug-in %s does not define load_file or save_file function",
193 PyString_AsString(repr));
200 Py_CLEAR(_entry_point);
208bool PythonLoaderFileType::
209ensure_loaded()
const {
210 if (_load_func !=
nullptr || _save_func !=
nullptr) {
213 nassertr_always(_entry_point !=
nullptr,
false);
215#if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS)
216 PyGILState_STATE gstate;
217 gstate = PyGILState_Ensure();
220 if (loader_cat.is_info()) {
221 PyObject *repr = PyObject_Repr(_entry_point);
224 <<
"loading file type module: "
225#if PY_MAJOR_VERSION >= 3
226 << PyUnicode_AsUTF8(repr) <<
"\n";
228 << PyString_AsString(repr) <<
"\n";
233 PyObject *result = PyObject_CallMethod(_entry_point, (
char *)
"load",
nullptr);
235 bool success =
false;
236 if (result !=
nullptr) {
237 success = ((PythonLoaderFileType *)
this)->init(result);
240 PyObject *repr = PyObject_Repr(_entry_point);
244#if PY_MAJOR_VERSION >= 3
245 << PyUnicode_AsUTF8(repr) <<
"\n";
247 << PyString_AsString(repr) <<
"\n";
252#if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS)
253 PyGILState_Release(gstate);
262std::string PythonLoaderFileType::
264 return "Python loader";
270std::string PythonLoaderFileType::
271get_extension()
const {
279std::string PythonLoaderFileType::
280get_additional_extensions()
const {
281 return _additional_extensions;
288bool PythonLoaderFileType::
289supports_compressed()
const {
290 return ensure_loaded() && _supports_compressed;
298bool PythonLoaderFileType::
299supports_load()
const {
300 return ensure_loaded() && _load_func !=
nullptr;
308bool PythonLoaderFileType::
309supports_save()
const {
310 return ensure_loaded() && _save_func !=
nullptr;
322 if (vfile ==
nullptr) {
326 if (!supports_load()) {
330 if (record !=
nullptr) {
334#if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS)
335 PyGILState_STATE gstate;
336 gstate = PyGILState_Ensure();
340 PyObject *args = PyTuple_New(3);
343 if (record !=
nullptr) {
345 PyTuple_SET_ITEM(args, 2, DTool_CreatePyInstanceTyped((
void *)record, Dtool_BamCacheRecord,
true,
false, record->
get_type_index()));
347 PyTuple_SET_ITEM(args, 2, Py_None);
353 PyObject *result = PythonThread::call_python_func(_load_func, args);
354 if (result !=
nullptr) {
355 if (DtoolInstance_Check(result)) {
356 node = (
PandaNode *)DtoolInstance_UPCAST(result, Dtool_PandaNode);
363 if (node ==
nullptr) {
364 PyObject *exc_type = _PyErr_OCCURRED();
367 <<
"load_file must return valid PandaNode or raise exception\n";
371 <<
" failed with " << ((PyTypeObject *)exc_type)->tp_name <<
" exception.\n";
376#if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS)
377 PyGILState_Release(gstate);
380 if (node !=
nullptr && node->is_of_type(ModelRoot::get_class_type())) {
392bool PythonLoaderFileType::
395 if (!supports_save()) {
399 nassertr(node !=
nullptr,
false);
402#if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS)
403 PyGILState_STATE gstate;
404 gstate = PyGILState_Ensure();
408 PyObject *args = PyTuple_New(3);
411 PyTuple_SET_ITEM(args, 2, DTool_CreatePyInstanceTyped((
void *)node, Dtool_PandaNode,
true,
false, node->get_type_index()));
413 PyObject *result = PythonThread::call_python_func(_load_func, args);
415 if (result !=
nullptr) {
420 <<
"save_file failed with an exception.\n";
423#if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS)
424 PyGILState_Release(gstate);
427 return (result !=
nullptr);
An instance of this class is written to the front of a Bam or Txo file to make the file a cached inst...
void add_dependent_file(const Filename &pathname)
Adds the indicated file to the list of files that will be loaded to generate the data in this record.
The name of a file, such as a texture file or an Egg file.
std::string get_basename() const
Returns the basename part of the filename.
Specifies parameters that may be passed to the loader.
A node of this type is created automatically at the root of each model file that is loaded.
set_fullpath
Sets the full pathname of the model represented by this node, as found on disk.
set_timestamp
Sets the timestamp of the file on disk that was read for this model.
A basic node of the scene graph or data graph.
void ref() const
Explicitly increments the reference count.
TypeHandle is the identifier used to differentiate C++ class types.
int get_type_index() const
Returns the internal index number associated with this object's TypeHandle, a unique number for each ...
A hierarchy of directories and files that appears to be one continuous file system,...
PointerTo< VirtualFile > get_file(const Filename &filename, bool status_only=false) const
Looks up the file by the indicated name in the file system.
static VirtualFileSystem * get_global_ptr()
Returns the default global VirtualFileSystem.
The abstract base class for a file or directory within the VirtualFileSystem.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PyObject * DTool_CreatePyInstance(const T *obj, bool memory_rules)
These functions wrap a pointer for a class that defines get_type_handle().
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.