Panda3D
|
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 }