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. 00168 return NULL; 00169 } 00170 00171 // Return the first file type associated with the given extension. 00172 return (*ei).second.front(); 00173 } 00174 00175 //////////////////////////////////////////////////////////////////// 00176 // Function: PNMFileTypeRegistry::get_type_from_magic_number 00177 // Access: Published 00178 // Description: Tries to determine what the PNMFileType is likely to 00179 // be for a particular image file based on its 00180 // magic number, the first two bytes read from the 00181 // file. Returns a suitable PNMFileType pointer, or 00182 // NULL if no type can be determined. 00183 //////////////////////////////////////////////////////////////////// 00184 PNMFileType *PNMFileTypeRegistry:: 00185 get_type_from_magic_number(const string &magic_number) const { 00186 if (_requires_sort) { 00187 ((PNMFileTypeRegistry *)this)->sort_preferences(); 00188 } 00189 00190 Types::const_iterator ti; 00191 for (ti = _types.begin(); ti != _types.end(); ++ti) { 00192 PNMFileType *type = (*ti); 00193 if (type->has_magic_number() && 00194 type->matches_magic_number(magic_number)) { 00195 return type; 00196 } 00197 } 00198 00199 return NULL; 00200 } 00201 00202 //////////////////////////////////////////////////////////////////// 00203 // Function: PNMFileTypeRegistry::get_type_by_handle 00204 // Access: Published 00205 // Description: Returns the PNMFileType instance stored in the 00206 // registry for the given TypeHandle, e.g. as retrieved 00207 // by a previous call to get_type() on the type 00208 // instance. 00209 //////////////////////////////////////////////////////////////////// 00210 PNMFileType *PNMFileTypeRegistry:: 00211 get_type_by_handle(TypeHandle handle) const { 00212 Handles::const_iterator hi; 00213 hi = _handles.find(handle); 00214 if (hi != _handles.end()) { 00215 return (*hi).second; 00216 } 00217 00218 return (PNMFileType *)NULL; 00219 } 00220 00221 //////////////////////////////////////////////////////////////////// 00222 // Function: PNMFileTypeRegistry::write 00223 // Access: Published 00224 // Description: Writes a list of supported image file types to the 00225 // indicated output stream, one per line. 00226 //////////////////////////////////////////////////////////////////// 00227 void PNMFileTypeRegistry:: 00228 write(ostream &out, int indent_level) const { 00229 if (_types.empty()) { 00230 indent(out, indent_level) << "(No image types are known).\n"; 00231 } else { 00232 Types::const_iterator ti; 00233 for (ti = _types.begin(); ti != _types.end(); ++ti) { 00234 PNMFileType *type = (*ti); 00235 string name = type->get_name(); 00236 indent(out, indent_level) << name; 00237 indent(out, max(30 - (int)name.length(), 0)) << " "; 00238 00239 int num_extensions = type->get_num_extensions(); 00240 if (num_extensions == 1) { 00241 out << "." << type->get_extension(0); 00242 } else if (num_extensions > 1) { 00243 out << "." << type->get_extension(0); 00244 for (int i = 1; i < num_extensions; i++) { 00245 out << ", ." << type->get_extension(i); 00246 } 00247 } 00248 out << "\n"; 00249 } 00250 } 00251 } 00252 00253 //////////////////////////////////////////////////////////////////// 00254 // Function: PNMFileTypeRegistry::get_global_ptr 00255 // Access: Published, Static 00256 // Description: Returns a pointer to the global PNMFileTypeRegistry 00257 // object. 00258 //////////////////////////////////////////////////////////////////// 00259 PNMFileTypeRegistry *PNMFileTypeRegistry:: 00260 get_global_ptr() { 00261 if (_global_ptr == (PNMFileTypeRegistry *)NULL) { 00262 _global_ptr = new PNMFileTypeRegistry; 00263 } 00264 return _global_ptr; 00265 } 00266 00267 //////////////////////////////////////////////////////////////////// 00268 // Function: PNMFileTypeRegistry::sort_preferences 00269 // Access: Private 00270 // Description: Sorts the PNMFileType pointers in order according to 00271 // user-specified preferences in the config file. This 00272 // allows us to choose a particular PNMFileType over 00273 // another for particular extensions when multiple file 00274 // types map to the same extension, or for file types 00275 // that have no magic number. 00276 //////////////////////////////////////////////////////////////////// 00277 void PNMFileTypeRegistry:: 00278 sort_preferences() { 00279 // So, we don't do anything here yet. One day we will. 00280 00281 _requires_sort = false; 00282 }