Panda3D
|
00001 // Filename: loaderFileTypeRegistry.cxx 00002 // Created by: drose (20Jun00) 00003 // 00004 //////////////////////////////////////////////////////////////////// 00005 // 00006 // PANDA 3D SOFTWARE 00007 // Copyright (c) Carnegie Mellon University. All rights reserved. 00008 // 00009 // All use of this software is subject to the terms of the revised BSD 00010 // license. You should have received a copy of this license along 00011 // with this source code in a file named "LICENSE." 00012 // 00013 //////////////////////////////////////////////////////////////////// 00014 00015 #include "loaderFileTypeRegistry.h" 00016 #include "loaderFileType.h" 00017 #include "config_pgraph.h" 00018 00019 #include "load_dso.h" 00020 #include "string_utils.h" 00021 #include "indent.h" 00022 00023 #include <algorithm> 00024 00025 LoaderFileTypeRegistry *LoaderFileTypeRegistry::_global_ptr; 00026 00027 //////////////////////////////////////////////////////////////////// 00028 // Function: LoaderFileTypeRegistry::Constructor 00029 // Access: Public 00030 // Description: 00031 //////////////////////////////////////////////////////////////////// 00032 LoaderFileTypeRegistry:: 00033 LoaderFileTypeRegistry() { 00034 } 00035 00036 //////////////////////////////////////////////////////////////////// 00037 // Function: LoaderFileTypeRegistry::Destructor 00038 // Access: Public 00039 // Description: 00040 //////////////////////////////////////////////////////////////////// 00041 LoaderFileTypeRegistry:: 00042 ~LoaderFileTypeRegistry() { 00043 } 00044 00045 //////////////////////////////////////////////////////////////////// 00046 // Function: LoaderFileTypeRegistry::register_type 00047 // Access: Public 00048 // Description: Defines a new LoaderFileType in the universe. 00049 //////////////////////////////////////////////////////////////////// 00050 void LoaderFileTypeRegistry:: 00051 register_type(LoaderFileType *type) { 00052 // Make sure we haven't already registered this type. 00053 if (find(_types.begin(), _types.end(), type) != _types.end()) { 00054 if (loader_cat->is_debug()) { 00055 loader_cat->debug() 00056 << "Attempt to register LoaderFileType " << type->get_name() 00057 << " (" << type->get_type() << ") more than once.\n"; 00058 } 00059 return; 00060 } 00061 00062 _types.push_back(type); 00063 00064 if (!type->get_extension().empty()) { 00065 record_extension(type->get_extension(), type); 00066 } 00067 00068 vector_string words; 00069 extract_words(type->get_additional_extensions(), words); 00070 vector_string::const_iterator wi; 00071 for (wi = words.begin(); wi != words.end(); ++wi) { 00072 record_extension(*wi, type); 00073 } 00074 } 00075 00076 //////////////////////////////////////////////////////////////////// 00077 // Function: LoaderFileTypeRegistry::register_deferred_type 00078 // Access: Public 00079 // Description: Records a type associated with a particular extension 00080 // to be loaded in the future. The named library will 00081 // be dynamically loaded the first time files of this 00082 // extension are loaded; presumably this library will 00083 // call register_type() when it initializes, thus making 00084 // the extension loadable. 00085 //////////////////////////////////////////////////////////////////// 00086 void LoaderFileTypeRegistry:: 00087 register_deferred_type(const string &extension, const string &library) { 00088 string dcextension = downcase(extension); 00089 00090 Extensions::const_iterator ei; 00091 ei = _extensions.find(dcextension); 00092 if (ei != _extensions.end()) { 00093 // We already have a loader for this type; no need to register 00094 // another one. 00095 if (loader_cat->is_debug()) { 00096 loader_cat->debug() 00097 << "Attempt to register loader library " << library 00098 << " (" << dcextension << ") when extension is already known.\n"; 00099 } 00100 return; 00101 } 00102 00103 DeferredTypes::const_iterator di; 00104 di = _deferred_types.find(dcextension); 00105 if (di != _deferred_types.end()) { 00106 if ((*di).second == library) { 00107 if (loader_cat->is_debug()) { 00108 loader_cat->debug() 00109 << "Attempt to register loader library " << library 00110 << " (" << dcextension << ") more than once.\n"; 00111 } 00112 return; 00113 } else { 00114 if (loader_cat->is_debug()) { 00115 loader_cat->debug() 00116 << "Multiple libraries registered that use the extension " 00117 << dcextension << "\n"; 00118 } 00119 } 00120 } 00121 00122 _deferred_types[dcextension] = library; 00123 } 00124 00125 //////////////////////////////////////////////////////////////////// 00126 // Function: LoaderFileTypeRegistry::get_num_types 00127 // Access: Published 00128 // Description: Returns the total number of types registered. 00129 //////////////////////////////////////////////////////////////////// 00130 int LoaderFileTypeRegistry:: 00131 get_num_types() const { 00132 return _types.size(); 00133 } 00134 00135 //////////////////////////////////////////////////////////////////// 00136 // Function: LoaderFileTypeRegistry::get_type 00137 // Access: Published 00138 // Description: Returns the nth type registered. 00139 //////////////////////////////////////////////////////////////////// 00140 LoaderFileType *LoaderFileTypeRegistry:: 00141 get_type(int n) const { 00142 nassertr(n >= 0 && n < (int)_types.size(), NULL); 00143 return _types[n]; 00144 } 00145 00146 //////////////////////////////////////////////////////////////////// 00147 // Function: LoaderFileTypeRegistry::get_type_from_extension 00148 // Access: Published 00149 // Description: Determines the type of the file based on the indicated 00150 // extension (without a leading dot). Returns NULL if 00151 // the extension matches no known file types. 00152 //////////////////////////////////////////////////////////////////// 00153 LoaderFileType *LoaderFileTypeRegistry:: 00154 get_type_from_extension(const string &extension) { 00155 string dcextension = downcase(extension); 00156 00157 Extensions::const_iterator ei; 00158 ei = _extensions.find(dcextension); 00159 if (ei == _extensions.end()) { 00160 // Nothing matches that extension. Do we have a deferred type? 00161 00162 DeferredTypes::iterator di; 00163 di = _deferred_types.find(dcextension); 00164 if (di != _deferred_types.end()) { 00165 // We do! Try to load the deferred library on-the-fly. Note 00166 // that this is a race condition if we support threaded loading; 00167 // this whole function needs to be protected from multiple 00168 // entry. 00169 string name = (*di).second; 00170 Filename dlname = Filename::dso_filename("lib" + name + ".so"); 00171 _deferred_types.erase(di); 00172 00173 loader_cat->info() 00174 << "loading file type module: " << name << endl; 00175 void *tmp = load_dso(get_plugin_path().get_value(), dlname); 00176 if (tmp == (void *)NULL) { 00177 loader_cat->warning() 00178 << "Unable to load " << dlname.to_os_specific() << ": " 00179 << load_dso_error() << endl; 00180 return NULL; 00181 } 00182 00183 // Now try again to find the LoaderFileType. 00184 ei = _extensions.find(dcextension); 00185 } 00186 } 00187 00188 if (ei == _extensions.end()) { 00189 // Nothing matches that extension, even after we've checked for a 00190 // deferred type description. 00191 return NULL; 00192 } 00193 00194 return (*ei).second; 00195 } 00196 00197 //////////////////////////////////////////////////////////////////// 00198 // Function: LoaderFileTypeRegistry::write 00199 // Access: Published 00200 // Description: Writes a list of supported file types to the 00201 // indicated output stream, one per line. 00202 //////////////////////////////////////////////////////////////////// 00203 void LoaderFileTypeRegistry:: 00204 write(ostream &out, int indent_level) const { 00205 if (_types.empty()) { 00206 indent(out, indent_level) << "(No file types are known).\n"; 00207 } else { 00208 Types::const_iterator ti; 00209 for (ti = _types.begin(); ti != _types.end(); ++ti) { 00210 LoaderFileType *type = (*ti); 00211 string name = type->get_name(); 00212 indent(out, indent_level) << name; 00213 indent(out, max(30 - (int)name.length(), 0)) << " "; 00214 00215 bool comma = false; 00216 if (!type->get_extension().empty()) { 00217 out << " ." << type->get_extension(); 00218 comma = true; 00219 } 00220 00221 vector_string words; 00222 extract_words(type->get_additional_extensions(), words); 00223 vector_string::const_iterator wi; 00224 for (wi = words.begin(); wi != words.end(); ++wi) { 00225 if (comma) { 00226 out << ","; 00227 } else { 00228 comma = true; 00229 } 00230 out << " ." << *wi; 00231 } 00232 out << "\n"; 00233 } 00234 } 00235 00236 if (!_deferred_types.empty()) { 00237 indent(out, indent_level) << "Also available:"; 00238 DeferredTypes::const_iterator di; 00239 for (di = _deferred_types.begin(); di != _deferred_types.end(); ++di) { 00240 const string &extension = (*di).first; 00241 out << " ." << extension; 00242 } 00243 out << "\n"; 00244 } 00245 } 00246 00247 //////////////////////////////////////////////////////////////////// 00248 // Function: LoaderFileTypeRegistry::get_global_ptr 00249 // Access: Published, Static 00250 // Description: Returns a pointer to the global LoaderFileTypeRegistry 00251 // object. 00252 //////////////////////////////////////////////////////////////////// 00253 LoaderFileTypeRegistry *LoaderFileTypeRegistry:: 00254 get_global_ptr() { 00255 if (_global_ptr == (LoaderFileTypeRegistry *)NULL) { 00256 _global_ptr = new LoaderFileTypeRegistry; 00257 } 00258 return _global_ptr; 00259 } 00260 00261 //////////////////////////////////////////////////////////////////// 00262 // Function: LoaderFileTypeRegistry::record_extension 00263 // Access: Private 00264 // Description: Records a filename extension recognized by a loader 00265 // file type. 00266 //////////////////////////////////////////////////////////////////// 00267 void LoaderFileTypeRegistry:: 00268 record_extension(const string &extension, LoaderFileType *type) { 00269 string dcextension = downcase(extension); 00270 Extensions::const_iterator ei; 00271 ei = _extensions.find(dcextension); 00272 if (ei != _extensions.end()) { 00273 if (loader_cat->is_debug()) { 00274 loader_cat->debug() 00275 << "Multiple LoaderFileTypes registered that use the extension " 00276 << dcextension << "\n"; 00277 } 00278 } else { 00279 _extensions.insert(Extensions::value_type(dcextension, type)); 00280 } 00281 00282 _deferred_types.erase(dcextension); 00283 }