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  * Returns the total number of types registered.
118  */
119 int LoaderFileTypeRegistry::
120 get_num_types() const {
121  return _types.size();
122 }
123 
124 /**
125  * Returns the nth type registered.
126  */
128 get_type(int n) const {
129  nassertr(n >= 0 && n < (int)_types.size(), nullptr);
130  return _types[n];
131 }
132 
133 /**
134  * Determines the type of the file based on the indicated extension (without a
135  * leading dot). Returns NULL if the extension matches no known file types.
136  */
138 get_type_from_extension(const string &extension) {
139  string dcextension = downcase(extension);
140 
141  Extensions::const_iterator ei;
142  ei = _extensions.find(dcextension);
143  if (ei == _extensions.end()) {
144  // Nothing matches that extension. Do we have a deferred type?
145 
146  DeferredTypes::iterator di;
147  di = _deferred_types.find(dcextension);
148  if (di != _deferred_types.end()) {
149  // We do! Try to load the deferred library on-the-fly. Note that this
150  // is a race condition if we support threaded loading; this whole
151  // function needs to be protected from multiple entry.
152  string name = (*di).second;
153  Filename dlname = Filename::dso_filename("lib" + name + ".so");
154  _deferred_types.erase(di);
155 
156  loader_cat->info()
157  << "loading file type module: " << name << std::endl;
158  void *tmp = load_dso(get_plugin_path().get_value(), dlname);
159  if (tmp == nullptr) {
160  loader_cat->warning()
161  << "Unable to load " << dlname.to_os_specific() << ": "
162  << load_dso_error() << std::endl;
163  return nullptr;
164  } else if (loader_cat.is_debug()) {
165  loader_cat.debug()
166  << "done loading file type module: " << name << std::endl;
167  }
168 
169  // Now try again to find the LoaderFileType.
170  ei = _extensions.find(dcextension);
171  }
172  }
173 
174  if (ei == _extensions.end()) {
175  // Nothing matches that extension, even after we've checked for a deferred
176  // type description.
177  return nullptr;
178  }
179 
180  return (*ei).second;
181 }
182 
183 /**
184  * Writes a list of supported file types to the indicated output stream, one
185  * per line.
186  */
188 write(std::ostream &out, int indent_level) const {
189  if (_types.empty()) {
190  indent(out, indent_level) << "(No file types are known).\n";
191  } else {
192  Types::const_iterator ti;
193  for (ti = _types.begin(); ti != _types.end(); ++ti) {
194  LoaderFileType *type = (*ti);
195  string name = type->get_name();
196  indent(out, indent_level) << name;
197  indent(out, std::max(30 - (int)name.length(), 0)) << " ";
198 
199  bool comma = false;
200  if (!type->get_extension().empty()) {
201  out << " ." << type->get_extension();
202  comma = true;
203  }
204 
205  vector_string words;
207  vector_string::const_iterator wi;
208  for (wi = words.begin(); wi != words.end(); ++wi) {
209  if (comma) {
210  out << ",";
211  } else {
212  comma = true;
213  }
214  out << " ." << *wi;
215  }
216  out << "\n";
217  }
218  }
219 
220  if (!_deferred_types.empty()) {
221  indent(out, indent_level) << "Also available:";
222  DeferredTypes::const_iterator di;
223  for (di = _deferred_types.begin(); di != _deferred_types.end(); ++di) {
224  const string &extension = (*di).first;
225  out << " ." << extension;
226  }
227  out << "\n";
228  }
229 }
230 
231 /**
232  * Returns a pointer to the global LoaderFileTypeRegistry object.
233  */
236  if (_global_ptr == nullptr) {
237  _global_ptr = new LoaderFileTypeRegistry;
238  }
239  return _global_ptr;
240 }
241 
242 /**
243  * Records a filename extension recognized by a loader file type.
244  */
245 void LoaderFileTypeRegistry::
246 record_extension(const string &extension, LoaderFileType *type) {
247  string dcextension = downcase(extension);
248  Extensions::const_iterator ei;
249  ei = _extensions.find(dcextension);
250  if (ei != _extensions.end()) {
251  if (loader_cat->is_debug()) {
252  loader_cat->debug()
253  << "Multiple LoaderFileTypes registered that use the extension "
254  << dcextension << "\n";
255  }
256  } else {
257  _extensions.insert(Extensions::value_type(dcextension, type));
258  }
259 
260  _deferred_types.erase(dcextension);
261 }
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.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
virtual std::string get_additional_extensions() const
Returns a space-separated list of extension, in addition to the one returned by get_extension(),...
static LoaderFileTypeRegistry * get_global_ptr()
Returns a pointer to the global LoaderFileTypeRegistry object.
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.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
string downcase(const string &s)
Returns the input string with all uppercase letters converted to lowercase.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void register_type(LoaderFileType *type)
Defines a new LoaderFileType in the universe.
int extract_words(const string &str, vector_string &words)
Divides the string into a number of words according to whitespace.
The name of a file, such as a texture file or an Egg file.
Definition: filename.h:39
std::ostream & indent(std::ostream &out, int indent_level)
A handy function for doing text formatting.
Definition: indent.cxx:20
get_type
Returns the nth type registered.
This class maintains the set of all known LoaderFileTypes in the universe.
LoaderFileType * get_type_from_extension(const std::string &extension)
Determines the type of the file based on the indicated extension (without a leading dot).
This is the base class for a family of scene-graph file types that the Loader supports.
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
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.