Panda3D
Loading...
Searching...
No Matches
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
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
24using std::string;
25
26LoaderFileTypeRegistry *LoaderFileTypeRegistry::_global_ptr;
27
28/**
29 *
30 */
31LoaderFileTypeRegistry::
32LoaderFileTypeRegistry() {
33}
34
35/**
36 *
37 */
38LoaderFileTypeRegistry::
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 */
78register_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 */
155get_num_types() const {
156 return _types.size();
157}
158
159/**
160 * Returns the nth type registered.
161 */
163get_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 */
173get_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 */
223write(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 */
280void LoaderFileTypeRegistry::
281record_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:44
std::string to_os_specific() const
Converts the filename from our generic Unix-like convention (forward slashes starting with the root a...
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.