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  */
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 }
indent
std::ostream & indent(std::ostream &out, int indent_level)
A handy function for doing text formatting.
Definition: indent.cxx:20
LoaderFileType
This is the base class for a family of scene-graph file types that the Loader supports.
Definition: loaderFileType.h:33
LoaderFileType::get_additional_extensions
virtual std::string get_additional_extensions() const
Returns a space-separated list of extension, in addition to the one returned by get_extension(),...
Definition: loaderFileType.cxx:45
string_utils.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
Filename::to_os_specific
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
LoaderFileTypeRegistry::write
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.
Definition: loaderFileTypeRegistry.cxx:223
load_dso.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
LoaderFileTypeRegistry::register_deferred_type
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.
Definition: loaderFileTypeRegistry.cxx:78
LoaderFileTypeRegistry::register_type
void register_type(LoaderFileType *type)
Defines a new LoaderFileType in the universe.
Definition: loaderFileTypeRegistry.cxx:46
downcase
string downcase(const string &s)
Returns the input string with all uppercase letters converted to lowercase.
Definition: string_utils.cxx:71
LoaderFileTypeRegistry
This class maintains the set of all known LoaderFileTypes in the universe.
Definition: loaderFileTypeRegistry.h:28
extract_words
int extract_words(const string &str, vector_string &words)
Divides the string into a number of words according to whitespace.
Definition: string_utils.cxx:105
loaderFileTypeRegistry.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
LoaderFileTypeRegistry::get_num_types
get_num_types
Returns the total number of types registered.
Definition: loaderFileTypeRegistry.h:48
LoaderFileTypeRegistry::get_global_ptr
static LoaderFileTypeRegistry * get_global_ptr()
Returns a pointer to the global LoaderFileTypeRegistry object.
Definition: loaderFileTypeRegistry.cxx:270
LoaderFileTypeRegistry::unregister_type
void unregister_type(LoaderFileType *type)
Removes a type previously registered using register_type.
Definition: loaderFileTypeRegistry.cxx:120
indent.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
config_pgraph.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
LoaderFileTypeRegistry::get_type
get_type
Returns the nth type registered.
Definition: loaderFileTypeRegistry.h:48
loaderFileType.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
Filename
The name of a file, such as a texture file or an Egg file.
Definition: filename.h:39
LoaderFileTypeRegistry::get_type_from_extension
LoaderFileType * get_type_from_extension(const std::string &extension)
Determines the type of the file based on the indicated extension (without a leading dot).
Definition: loaderFileTypeRegistry.cxx:173