Panda3D
loaderFileTypeRegistry.cxx
1 // Filename: loaderFileTypeRegistry.cxx
2 // Created by: drose (20Jun00)
3 //
4 ////////////////////////////////////////////////////////////////////
5 //
6 // PANDA 3D SOFTWARE
7 // Copyright (c) Carnegie Mellon University. All rights reserved.
8 //
9 // All use of this software is subject to the terms of the revised BSD
10 // license. You should have received a copy of this license along
11 // with this source code in a file named "LICENSE."
12 //
13 ////////////////////////////////////////////////////////////////////
14 
15 #include "loaderFileTypeRegistry.h"
16 #include "loaderFileType.h"
17 #include "config_pgraph.h"
18 
19 #include "load_dso.h"
20 #include "string_utils.h"
21 #include "indent.h"
22 
23 #include <algorithm>
24 
25 LoaderFileTypeRegistry *LoaderFileTypeRegistry::_global_ptr;
26 
27 ////////////////////////////////////////////////////////////////////
28 // Function: LoaderFileTypeRegistry::Constructor
29 // Access: Public
30 // Description:
31 ////////////////////////////////////////////////////////////////////
32 LoaderFileTypeRegistry::
33 LoaderFileTypeRegistry() {
34 }
35 
36 ////////////////////////////////////////////////////////////////////
37 // Function: LoaderFileTypeRegistry::Destructor
38 // Access: Public
39 // Description:
40 ////////////////////////////////////////////////////////////////////
41 LoaderFileTypeRegistry::
42 ~LoaderFileTypeRegistry() {
43 }
44 
45 ////////////////////////////////////////////////////////////////////
46 // Function: LoaderFileTypeRegistry::register_type
47 // Access: Public
48 // Description: Defines a new LoaderFileType in the universe.
49 ////////////////////////////////////////////////////////////////////
52  // Make sure we haven't already registered this type.
53  if (find(_types.begin(), _types.end(), type) != _types.end()) {
54  if (loader_cat->is_debug()) {
55  loader_cat->debug()
56  << "Attempt to register LoaderFileType " << type->get_name()
57  << " (" << type->get_type() << ") more than once.\n";
58  }
59  return;
60  }
61 
62  _types.push_back(type);
63 
64  if (!type->get_extension().empty()) {
65  record_extension(type->get_extension(), type);
66  }
67 
68  vector_string words;
69  extract_words(type->get_additional_extensions(), words);
70  vector_string::const_iterator wi;
71  for (wi = words.begin(); wi != words.end(); ++wi) {
72  record_extension(*wi, type);
73  }
74 }
75 
76 ////////////////////////////////////////////////////////////////////
77 // Function: LoaderFileTypeRegistry::register_deferred_type
78 // Access: Public
79 // Description: Records a type associated with a particular extension
80 // to be loaded in the future. The named library will
81 // be dynamically loaded the first time files of this
82 // extension are loaded; presumably this library will
83 // call register_type() when it initializes, thus making
84 // the extension loadable.
85 ////////////////////////////////////////////////////////////////////
87 register_deferred_type(const string &extension, const string &library) {
88  string dcextension = downcase(extension);
89 
90  Extensions::const_iterator ei;
91  ei = _extensions.find(dcextension);
92  if (ei != _extensions.end()) {
93  // We already have a loader for this type; no need to register
94  // another one.
95  if (loader_cat->is_debug()) {
96  loader_cat->debug()
97  << "Attempt to register loader library " << library
98  << " (" << dcextension << ") when extension is already known.\n";
99  }
100  return;
101  }
102 
103  DeferredTypes::const_iterator di;
104  di = _deferred_types.find(dcextension);
105  if (di != _deferred_types.end()) {
106  if ((*di).second == library) {
107  if (loader_cat->is_debug()) {
108  loader_cat->debug()
109  << "Attempt to register loader library " << library
110  << " (" << dcextension << ") more than once.\n";
111  }
112  return;
113  } else {
114  if (loader_cat->is_debug()) {
115  loader_cat->debug()
116  << "Multiple libraries registered that use the extension "
117  << dcextension << "\n";
118  }
119  }
120  }
121 
122  _deferred_types[dcextension] = library;
123 }
124 
125 ////////////////////////////////////////////////////////////////////
126 // Function: LoaderFileTypeRegistry::get_num_types
127 // Access: Published
128 // Description: Returns the total number of types registered.
129 ////////////////////////////////////////////////////////////////////
131 get_num_types() const {
132  return _types.size();
133 }
134 
135 ////////////////////////////////////////////////////////////////////
136 // Function: LoaderFileTypeRegistry::get_type
137 // Access: Published
138 // Description: Returns the nth type registered.
139 ////////////////////////////////////////////////////////////////////
141 get_type(int n) const {
142  nassertr(n >= 0 && n < (int)_types.size(), NULL);
143  return _types[n];
144 }
145 
146 ////////////////////////////////////////////////////////////////////
147 // Function: LoaderFileTypeRegistry::get_type_from_extension
148 // Access: Published
149 // Description: Determines the type of the file based on the indicated
150 // extension (without a leading dot). Returns NULL if
151 // the extension matches no known file types.
152 ////////////////////////////////////////////////////////////////////
154 get_type_from_extension(const string &extension) {
155  string dcextension = downcase(extension);
156 
157  Extensions::const_iterator ei;
158  ei = _extensions.find(dcextension);
159  if (ei == _extensions.end()) {
160  // Nothing matches that extension. Do we have a deferred type?
161 
162  DeferredTypes::iterator di;
163  di = _deferred_types.find(dcextension);
164  if (di != _deferred_types.end()) {
165  // We do! Try to load the deferred library on-the-fly. Note
166  // that this is a race condition if we support threaded loading;
167  // this whole function needs to be protected from multiple
168  // entry.
169  string name = (*di).second;
170  Filename dlname = Filename::dso_filename("lib" + name + ".so");
171  _deferred_types.erase(di);
172 
173  loader_cat->info()
174  << "loading file type module: " << name << endl;
175  void *tmp = load_dso(get_plugin_path().get_value(), dlname);
176  if (tmp == (void *)NULL) {
177  loader_cat->warning()
178  << "Unable to load " << dlname.to_os_specific() << ": "
179  << load_dso_error() << endl;
180  return NULL;
181  } else if (loader_cat.is_debug()) {
182  loader_cat.debug()
183  << "done loading file type module: " << name << endl;
184  }
185 
186  // Now try again to find the LoaderFileType.
187  ei = _extensions.find(dcextension);
188  }
189  }
190 
191  if (ei == _extensions.end()) {
192  // Nothing matches that extension, even after we've checked for a
193  // deferred type description.
194  return NULL;
195  }
196 
197  return (*ei).second;
198 }
199 
200 ////////////////////////////////////////////////////////////////////
201 // Function: LoaderFileTypeRegistry::write
202 // Access: Published
203 // Description: Writes a list of supported file types to the
204 // indicated output stream, one per line.
205 ////////////////////////////////////////////////////////////////////
207 write(ostream &out, int indent_level) const {
208  if (_types.empty()) {
209  indent(out, indent_level) << "(No file types are known).\n";
210  } else {
211  Types::const_iterator ti;
212  for (ti = _types.begin(); ti != _types.end(); ++ti) {
213  LoaderFileType *type = (*ti);
214  string name = type->get_name();
215  indent(out, indent_level) << name;
216  indent(out, max(30 - (int)name.length(), 0)) << " ";
217 
218  bool comma = false;
219  if (!type->get_extension().empty()) {
220  out << " ." << type->get_extension();
221  comma = true;
222  }
223 
224  vector_string words;
225  extract_words(type->get_additional_extensions(), words);
226  vector_string::const_iterator wi;
227  for (wi = words.begin(); wi != words.end(); ++wi) {
228  if (comma) {
229  out << ",";
230  } else {
231  comma = true;
232  }
233  out << " ." << *wi;
234  }
235  out << "\n";
236  }
237  }
238 
239  if (!_deferred_types.empty()) {
240  indent(out, indent_level) << "Also available:";
241  DeferredTypes::const_iterator di;
242  for (di = _deferred_types.begin(); di != _deferred_types.end(); ++di) {
243  const string &extension = (*di).first;
244  out << " ." << extension;
245  }
246  out << "\n";
247  }
248 }
249 
250 ////////////////////////////////////////////////////////////////////
251 // Function: LoaderFileTypeRegistry::get_global_ptr
252 // Access: Published, Static
253 // Description: Returns a pointer to the global LoaderFileTypeRegistry
254 // object.
255 ////////////////////////////////////////////////////////////////////
258  if (_global_ptr == (LoaderFileTypeRegistry *)NULL) {
259  _global_ptr = new LoaderFileTypeRegistry;
260  }
261  return _global_ptr;
262 }
263 
264 ////////////////////////////////////////////////////////////////////
265 // Function: LoaderFileTypeRegistry::record_extension
266 // Access: Private
267 // Description: Records a filename extension recognized by a loader
268 // file type.
269 ////////////////////////////////////////////////////////////////////
270 void LoaderFileTypeRegistry::
271 record_extension(const string &extension, LoaderFileType *type) {
272  string dcextension = downcase(extension);
273  Extensions::const_iterator ei;
274  ei = _extensions.find(dcextension);
275  if (ei != _extensions.end()) {
276  if (loader_cat->is_debug()) {
277  loader_cat->debug()
278  << "Multiple LoaderFileTypes registered that use the extension "
279  << dcextension << "\n";
280  }
281  } else {
282  _extensions.insert(Extensions::value_type(dcextension, type));
283  }
284 
285  _deferred_types.erase(dcextension);
286 }
static LoaderFileTypeRegistry * get_global_ptr()
Returns a pointer to the global LoaderFileTypeRegistry object.
void write(ostream &out, int indent_level=0) const
Writes a list of supported file types to the indicated output stream, one per line.
LoaderFileType * get_type(int n) const
Returns the nth type registered.
virtual string get_additional_extensions() const
Returns a space-separated list of extension, in addition to the one returned by get_extension(), that are recognized by this loader.
int get_num_types() const
Returns the total number of types registered.
void register_type(LoaderFileType *type)
Defines a new LoaderFileType in the universe.
void register_deferred_type(const string &extension, const string &library)
Records a type associated with a particular extension to be loaded in the future. ...
The name of a file, such as a texture file or an Egg file.
Definition: filename.h:44
LoaderFileType * get_type_from_extension(const string &extension)
Determines the type of the file based on the indicated extension (without a leading dot)...
This class maintains the set of all known LoaderFileTypes in the universe.
This is the base class for a family of scene-graph file types that the Loader supports.
string to_os_specific() const
Converts the filename from our generic Unix-like convention (forward slashes starting with the root a...
Definition: filename.cxx:1196