Panda3D
 All Classes Functions Variables Enumerations
loaderFileTypeRegistry.cxx
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 }
 All Classes Functions Variables Enumerations