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 record_extension(type->get_extension(), type); 00065 00066 vector_string words; 00067 extract_words(type->get_additional_extensions(), words); 00068 vector_string::const_iterator wi; 00069 for (wi = words.begin(); wi != words.end(); ++wi) { 00070 record_extension(*wi, type); 00071 } 00072 } 00073 00074 //////////////////////////////////////////////////////////////////// 00075 // Function: LoaderFileTypeRegistry::register_deferred_type 00076 // Access: Public 00077 // Description: Records a type associated with a particular extension 00078 // to be loaded in the future. The named library will 00079 // be dynamically loaded the first time files of this 00080 // extension are loaded; presumably this library will 00081 // call register_type() when it initializes, thus making 00082 // the extension loadable. 00083 //////////////////////////////////////////////////////////////////// 00084 void LoaderFileTypeRegistry:: 00085 register_deferred_type(const string &extension, const string &library) { 00086 string dcextension = downcase(extension); 00087 00088 Extensions::const_iterator ei; 00089 ei = _extensions.find(dcextension); 00090 if (ei != _extensions.end()) { 00091 // We already have a loader for this type; no need to register 00092 // another one. 00093 if (loader_cat->is_debug()) { 00094 loader_cat->debug() 00095 << "Attempt to register loader library " << library 00096 << " (" << dcextension << ") when extension is already known.\n"; 00097 } 00098 return; 00099 } 00100 00101 DeferredTypes::const_iterator di; 00102 di = _deferred_types.find(dcextension); 00103 if (di != _deferred_types.end()) { 00104 if ((*di).second == library) { 00105 if (loader_cat->is_debug()) { 00106 loader_cat->debug() 00107 << "Attempt to register loader library " << library 00108 << " (" << dcextension << ") more than once.\n"; 00109 } 00110 return; 00111 } else { 00112 if (loader_cat->is_debug()) { 00113 loader_cat->debug() 00114 << "Multiple libraries registered that use the extension " 00115 << dcextension << "\n"; 00116 } 00117 } 00118 } 00119 00120 _deferred_types[dcextension] = library; 00121 } 00122 00123 //////////////////////////////////////////////////////////////////// 00124 // Function: LoaderFileTypeRegistry::get_num_types 00125 // Access: Published 00126 // Description: Returns the total number of types registered. 00127 //////////////////////////////////////////////////////////////////// 00128 int LoaderFileTypeRegistry:: 00129 get_num_types() const { 00130 return _types.size(); 00131 } 00132 00133 //////////////////////////////////////////////////////////////////// 00134 // Function: LoaderFileTypeRegistry::get_type 00135 // Access: Published 00136 // Description: Returns the nth type registered. 00137 //////////////////////////////////////////////////////////////////// 00138 LoaderFileType *LoaderFileTypeRegistry:: 00139 get_type(int n) const { 00140 nassertr(n >= 0 && n < (int)_types.size(), NULL); 00141 return _types[n]; 00142 } 00143 00144 //////////////////////////////////////////////////////////////////// 00145 // Function: LoaderFileTypeRegistry::get_type_from_extension 00146 // Access: Published 00147 // Description: Determines the type of the file based on the indicated 00148 // extension (without a leading dot). Returns NULL if 00149 // the extension matches no known file types. 00150 //////////////////////////////////////////////////////////////////// 00151 LoaderFileType *LoaderFileTypeRegistry:: 00152 get_type_from_extension(const string &extension) { 00153 string dcextension = downcase(extension); 00154 00155 Extensions::const_iterator ei; 00156 ei = _extensions.find(dcextension); 00157 if (ei == _extensions.end()) { 00158 // Nothing matches that extension. Do we have a deferred type? 00159 00160 DeferredTypes::iterator di; 00161 di = _deferred_types.find(dcextension); 00162 if (di != _deferred_types.end()) { 00163 // We do! Try to load the deferred library on-the-fly. Note 00164 // that this is a race condition if we support threaded loading; 00165 // this whole function needs to be protected from multiple 00166 // entry. 00167 string name = (*di).second; 00168 Filename dlname = Filename::dso_filename("lib" + name + ".so"); 00169 _deferred_types.erase(di); 00170 00171 loader_cat->info() 00172 << "loading file type module: " << name << endl; 00173 void *tmp = load_dso(get_plugin_path().get_value(), dlname); 00174 if (tmp == (void *)NULL) { 00175 loader_cat->warning() 00176 << "Unable to load " << dlname.to_os_specific() << ": " 00177 << load_dso_error() << endl; 00178 return NULL; 00179 } 00180 00181 // Now try again to find the LoaderFileType. 00182 ei = _extensions.find(dcextension); 00183 } 00184 } 00185 00186 if (ei == _extensions.end()) { 00187 // Nothing matches that extension, even after we've checked for a 00188 // deferred type description. 00189 return NULL; 00190 } 00191 00192 return (*ei).second; 00193 } 00194 00195 //////////////////////////////////////////////////////////////////// 00196 // Function: LoaderFileTypeRegistry::write 00197 // Access: Published 00198 // Description: Writes a list of supported file types to the 00199 // indicated output stream, one per line. 00200 //////////////////////////////////////////////////////////////////// 00201 void LoaderFileTypeRegistry:: 00202 write(ostream &out, int indent_level) const { 00203 if (_types.empty()) { 00204 indent(out, indent_level) << "(No file types are known).\n"; 00205 } else { 00206 Types::const_iterator ti; 00207 for (ti = _types.begin(); ti != _types.end(); ++ti) { 00208 LoaderFileType *type = (*ti); 00209 string name = type->get_name(); 00210 indent(out, indent_level) << name; 00211 indent(out, max(30 - (int)name.length(), 0)) 00212 << " ." << type->get_extension() << "\n"; 00213 } 00214 } 00215 00216 if (!_deferred_types.empty()) { 00217 indent(out, indent_level) << "Also available:"; 00218 DeferredTypes::const_iterator di; 00219 for (di = _deferred_types.begin(); di != _deferred_types.end(); ++di) { 00220 const string &extension = (*di).first; 00221 out << " ." << extension; 00222 } 00223 out << "\n"; 00224 } 00225 } 00226 00227 //////////////////////////////////////////////////////////////////// 00228 // Function: LoaderFileTypeRegistry::get_global_ptr 00229 // Access: Published, Static 00230 // Description: Returns a pointer to the global LoaderFileTypeRegistry 00231 // object. 00232 //////////////////////////////////////////////////////////////////// 00233 LoaderFileTypeRegistry *LoaderFileTypeRegistry:: 00234 get_global_ptr() { 00235 if (_global_ptr == (LoaderFileTypeRegistry *)NULL) { 00236 _global_ptr = new LoaderFileTypeRegistry; 00237 } 00238 return _global_ptr; 00239 } 00240 00241 //////////////////////////////////////////////////////////////////// 00242 // Function: LoaderFileTypeRegistry::record_extension 00243 // Access: Private 00244 // Description: Records a filename extension recognized by a loader 00245 // file type. 00246 //////////////////////////////////////////////////////////////////// 00247 void LoaderFileTypeRegistry:: 00248 record_extension(const string &extension, LoaderFileType *type) { 00249 string dcextension = downcase(extension); 00250 Extensions::const_iterator ei; 00251 ei = _extensions.find(dcextension); 00252 if (ei != _extensions.end()) { 00253 if (loader_cat->is_debug()) { 00254 loader_cat->debug() 00255 << "Multiple LoaderFileTypes registered that use the extension " 00256 << dcextension << "\n"; 00257 } 00258 } else { 00259 _extensions.insert(Extensions::value_type(dcextension, type)); 00260 } 00261 00262 _deferred_types.erase(dcextension); 00263 }