Panda3D

pnmFileTypeRegistry.cxx

00001 // Filename: pnmFileTypeRegistry.cxx
00002 // Created by:  drose (15Jun00)
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 "pnmFileTypeRegistry.h"
00016 #include "pnmFileType.h"
00017 #include "config_pnmimage.h"
00018 
00019 #include "string_utils.h"
00020 #include "indent.h"
00021 #include "pset.h"
00022 
00023 #include <algorithm>
00024 
00025 PNMFileTypeRegistry *PNMFileTypeRegistry::_global_ptr;
00026 
00027 ////////////////////////////////////////////////////////////////////
00028 //     Function: PNMFileTypeRegistry::Constructor
00029 //       Access: Public
00030 //  Description:
00031 ////////////////////////////////////////////////////////////////////
00032 PNMFileTypeRegistry::
00033 PNMFileTypeRegistry() {
00034   _requires_sort = false;
00035 }
00036 
00037 ////////////////////////////////////////////////////////////////////
00038 //     Function: PNMFileTypeRegistry::Destructor
00039 //       Access: Public
00040 //  Description:
00041 ////////////////////////////////////////////////////////////////////
00042 PNMFileTypeRegistry::
00043 ~PNMFileTypeRegistry() {
00044 }
00045 
00046 ////////////////////////////////////////////////////////////////////
00047 //     Function: PNMFileTypeRegistry::register_type
00048 //       Access: Public
00049 //  Description: Defines a new PNMFileType in the universe.
00050 ////////////////////////////////////////////////////////////////////
00051 void PNMFileTypeRegistry::
00052 register_type(PNMFileType *type) {
00053   if (pnmimage_cat->is_debug()) {
00054     pnmimage_cat->debug()
00055       << "Registering image type " << type->get_name() << "\n";
00056   }
00057 
00058   // Make sure we haven't already registered this type.
00059   Handles::iterator hi = _handles.find(type->get_type());
00060   if (hi != _handles.end()) {
00061     pnmimage_cat->warning()
00062       << "Attempt to register PNMFileType " << type->get_name()
00063       << " (" << type->get_type() << ") more than once.\n";
00064     return;
00065   }
00066 
00067   _types.push_back(type);
00068   _handles.insert(Handles::value_type(type->get_type(), type));
00069 
00070   // Collect the unique extensions associated with the type.
00071   pset<string> unique_extensions;
00072   int num_extensions = type->get_num_extensions();
00073   for (int i = 0; i < num_extensions; i++) {
00074     string extension = downcase(type->get_extension(i));
00075 
00076     if (!unique_extensions.insert(extension).second) {
00077       pnmimage_cat->warning()
00078         << "PNMFileType " << type->get_name()
00079         << " (" << type->get_type() << ") defined extension "
00080         << extension << " more than once.\n";
00081     }
00082   }
00083 
00084   pset<string>::iterator ui;
00085   for (ui = unique_extensions.begin(); ui != unique_extensions.end(); ++ui) {
00086     _extensions[*ui].push_back(type);
00087   }
00088 
00089   _requires_sort = true;
00090 }
00091 
00092 ////////////////////////////////////////////////////////////////////
00093 //     Function: PNMFileTypeRegistry::get_num_types
00094 //       Access: Published
00095 //  Description: Returns the total number of types registered.
00096 ////////////////////////////////////////////////////////////////////
00097 int PNMFileTypeRegistry::
00098 get_num_types() const {
00099   if (_requires_sort) {
00100     ((PNMFileTypeRegistry *)this)->sort_preferences();
00101   }
00102   return _types.size();
00103 }
00104 
00105 ////////////////////////////////////////////////////////////////////
00106 //     Function: PNMFileTypeRegistry::get_type
00107 //       Access: Published
00108 //  Description: Returns the nth type registered.
00109 ////////////////////////////////////////////////////////////////////
00110 PNMFileType *PNMFileTypeRegistry::
00111 get_type(int n) const {
00112   nassertr(n >= 0 && n < (int)_types.size(), NULL);
00113   return _types[n];
00114 }
00115 
00116 ////////////////////////////////////////////////////////////////////
00117 //     Function: PNMFileTypeRegistry::get_type_from_extension
00118 //       Access: Published
00119 //  Description: Tries to determine what the PNMFileType is likely to
00120 //               be for a particular image file based on its
00121 //               extension.  Returns a suitable PNMFileType pointer,
00122 //               or NULL if no type can be determined.
00123 ////////////////////////////////////////////////////////////////////
00124 PNMFileType *PNMFileTypeRegistry::
00125 get_type_from_extension(const string &filename) const {
00126   if (_requires_sort) {
00127     ((PNMFileTypeRegistry *)this)->sort_preferences();
00128   }
00129 
00130   // Extract the extension from the filename; if there is no dot, use
00131   // the whole filename as the extension.  This allows us to pass in
00132   // just a dotless extension name in lieu of a filename.
00133 
00134   string extension;
00135   size_t dot = filename.rfind('.');
00136 
00137   if (dot == string::npos) {
00138     extension = filename;
00139   } else {
00140     extension = filename.substr(dot + 1);
00141   }
00142 
00143 #ifdef HAVE_ZLIB
00144   if (extension == "pz") {
00145     // If the extension is .pz, then we've got a Panda-compressed
00146     // image file.  Back up some more and get the extension before
00147     // that.
00148     size_t prev_dot = filename.rfind('.', dot - 1);
00149     if (prev_dot == string::npos) {
00150       extension = filename.substr(0, dot);
00151     } else {
00152       extension = filename.substr(prev_dot + 1, dot - prev_dot - 1);
00153     }
00154   }
00155 #endif  // HAVE_ZLIB
00156 
00157   if (extension.find('/') != string::npos) {
00158     // If we picked the whole filename and it contains slashes, or if
00159     // the rightmost dot wasn't in the basename of the filename, then
00160     // it's actually a filename without an extension.
00161     extension = "";
00162   }
00163 
00164   Extensions::const_iterator ei;
00165   ei = _extensions.find(extension);
00166   if (ei == _extensions.end() || (*ei).second.empty()) {
00167     // Nothing matches that string.  Try again with a downcased string
00168     // in case we got an all-uppercase filename (most of our
00169     // extensions are downcased).
00170     ei = _extensions.find(downcase(extension));
00171 
00172     if (ei == _extensions.end() || (*ei).second.empty()) {
00173       // Nothing matches that string.
00174       return NULL;
00175     }
00176   }
00177 
00178   // Return the first file type associated with the given extension.
00179   return (*ei).second.front();
00180 }
00181 
00182 ////////////////////////////////////////////////////////////////////
00183 //     Function: PNMFileTypeRegistry::get_type_from_magic_number
00184 //       Access: Published
00185 //  Description: Tries to determine what the PNMFileType is likely to
00186 //               be for a particular image file based on its
00187 //               magic number, the first two bytes read from the
00188 //               file.  Returns a suitable PNMFileType pointer, or
00189 //               NULL if no type can be determined.
00190 ////////////////////////////////////////////////////////////////////
00191 PNMFileType *PNMFileTypeRegistry::
00192 get_type_from_magic_number(const string &magic_number) const {
00193   if (_requires_sort) {
00194     ((PNMFileTypeRegistry *)this)->sort_preferences();
00195   }
00196 
00197   Types::const_iterator ti;
00198   for (ti = _types.begin(); ti != _types.end(); ++ti) {
00199     PNMFileType *type = (*ti);
00200     if (type->has_magic_number() &&
00201         type->matches_magic_number(magic_number)) {
00202       return type;
00203     }
00204   }
00205 
00206   return NULL;
00207 }
00208 
00209 ////////////////////////////////////////////////////////////////////
00210 //     Function: PNMFileTypeRegistry::get_type_by_handle
00211 //       Access: Published
00212 //  Description: Returns the PNMFileType instance stored in the
00213 //               registry for the given TypeHandle, e.g. as retrieved
00214 //               by a previous call to get_type() on the type
00215 //               instance.
00216 ////////////////////////////////////////////////////////////////////
00217 PNMFileType *PNMFileTypeRegistry::
00218 get_type_by_handle(TypeHandle handle) const {
00219   Handles::const_iterator hi;
00220   hi = _handles.find(handle);
00221   if (hi != _handles.end()) {
00222     return (*hi).second;
00223   }
00224 
00225   return (PNMFileType *)NULL;
00226 }
00227 
00228 ////////////////////////////////////////////////////////////////////
00229 //     Function: PNMFileTypeRegistry::write
00230 //       Access: Published
00231 //  Description: Writes a list of supported image file types to the
00232 //               indicated output stream, one per line.
00233 ////////////////////////////////////////////////////////////////////
00234 void PNMFileTypeRegistry::
00235 write(ostream &out, int indent_level) const {
00236   if (_types.empty()) {
00237     indent(out, indent_level) << "(No image types are known).\n";
00238   } else {
00239     Types::const_iterator ti;
00240     for (ti = _types.begin(); ti != _types.end(); ++ti) {
00241       PNMFileType *type = (*ti);
00242       string name = type->get_name();
00243       indent(out, indent_level) << name;
00244       indent(out, max(30 - (int)name.length(), 0)) << "  ";
00245 
00246       int num_extensions = type->get_num_extensions();
00247       if (num_extensions == 1) {
00248         out << "." << type->get_extension(0);
00249       } else if (num_extensions > 1) {
00250         out << "." << type->get_extension(0);
00251         for (int i = 1; i < num_extensions; i++) {
00252           out << ", ." << type->get_extension(i);
00253         }
00254       }
00255       out << "\n";
00256     }
00257   }
00258 }
00259 
00260 ////////////////////////////////////////////////////////////////////
00261 //     Function: PNMFileTypeRegistry::get_global_ptr
00262 //       Access: Published, Static
00263 //  Description: Returns a pointer to the global PNMFileTypeRegistry
00264 //               object.
00265 ////////////////////////////////////////////////////////////////////
00266 PNMFileTypeRegistry *PNMFileTypeRegistry::
00267 get_global_ptr() {
00268   if (_global_ptr == (PNMFileTypeRegistry *)NULL) {
00269     _global_ptr = new PNMFileTypeRegistry;
00270   }
00271   return _global_ptr;
00272 }
00273 
00274 ////////////////////////////////////////////////////////////////////
00275 //     Function: PNMFileTypeRegistry::sort_preferences
00276 //       Access: Private
00277 //  Description: Sorts the PNMFileType pointers in order according to
00278 //               user-specified preferences in the config file.  This
00279 //               allows us to choose a particular PNMFileType over
00280 //               another for particular extensions when multiple file
00281 //               types map to the same extension, or for file types
00282 //               that have no magic number.
00283 ////////////////////////////////////////////////////////////////////
00284 void PNMFileTypeRegistry::
00285 sort_preferences() {
00286   // So, we don't do anything here yet.  One day we will.
00287 
00288   _requires_sort = false;
00289 }
 All Classes Functions Variables Enumerations