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