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