Panda3D
pnmFileTypeRegistry.cxx
Go to the documentation of this file.
1 /**
2  * PANDA 3D SOFTWARE
3  * Copyright (c) Carnegie Mellon University. All rights reserved.
4  *
5  * All use of this software is subject to the terms of the revised BSD
6  * license. You should have received a copy of this license along
7  * with this source code in a file named "LICENSE."
8  *
9  * @file pnmFileTypeRegistry.cxx
10  * @author drose
11  * @date 2000-06-15
12  */
13 
14 #include "pnmFileTypeRegistry.h"
15 #include "pnmFileType.h"
16 #include "config_pnmimage.h"
17 
18 #include "string_utils.h"
19 #include "indent.h"
20 #include "pset.h"
21 
22 #include <algorithm>
23 
24 using std::string;
25 
26 PNMFileTypeRegistry *PNMFileTypeRegistry::_global_ptr;
27 
28 /**
29  *
30  */
31 PNMFileTypeRegistry::
32 PNMFileTypeRegistry() {
33  _requires_sort = false;
34 }
35 
36 /**
37  *
38  */
39 PNMFileTypeRegistry::
40 ~PNMFileTypeRegistry() {
41 }
42 
43 /**
44  * Defines a new PNMFileType in the universe.
45  */
48  if (pnmimage_cat->is_debug()) {
49  pnmimage_cat->debug()
50  << "Registering image type " << type->get_name() << "\n";
51  }
52 
53  // Make sure we haven't already registered this type.
54  TypeHandle handle = type->get_type();
55  if (handle != PNMFileType::get_class_type()) {
56  Handles::iterator hi = _handles.find(handle);
57  if (hi != _handles.end()) {
58  pnmimage_cat->warning()
59  << "Attempt to register PNMFileType " << type->get_name()
60  << " (" << type->get_type() << ") more than once.\n";
61  return;
62  }
63  _handles.insert(Handles::value_type(handle, type));
64  }
65 
66  _types.push_back(type);
67 
68  // Collect the unique extensions associated with the type.
69  pset<string> unique_extensions;
70  int num_extensions = type->get_num_extensions();
71  for (int i = 0; i < num_extensions; i++) {
72  string extension = downcase(type->get_extension(i));
73 
74  if (!unique_extensions.insert(extension).second) {
75  pnmimage_cat->warning()
76  << "PNMFileType " << type->get_name()
77  << " (" << type->get_type() << ") defined extension "
78  << extension << " more than once.\n";
79  }
80  }
81 
83  for (ui = unique_extensions.begin(); ui != unique_extensions.end(); ++ui) {
84  _extensions[*ui].push_back(type);
85  }
86 
87  _requires_sort = true;
88 }
89 
90 /**
91  * Removes a PNMFileType previously passed to register_type.
92  */
95  if (pnmimage_cat->is_debug()) {
96  pnmimage_cat->debug()
97  << "Unregistering image type " << type->get_name() << "\n";
98  }
99 
100  TypeHandle handle = type->get_type();
101  if (handle != PNMFileType::get_class_type()) {
102  Handles::iterator hi = _handles.find(handle);
103  if (hi != _handles.end()) {
104  _handles.erase(hi);
105  }
106  }
107 
108  _types.erase(std::remove(_types.begin(), _types.end(), type),
109  _types.end());
110 
111  Extensions::iterator ei;
112  for (ei = _extensions.begin(); ei != _extensions.end(); ++ei) {
113  Types &types = ei->second;
114  types.erase(std::remove(types.begin(), types.end(), type),
115  types.end());
116  }
117 
118  _requires_sort = true;
119 }
120 
121 /**
122  * Returns the total number of types registered.
123  */
124 int PNMFileTypeRegistry::
125 get_num_types() const {
126  if (_requires_sort) {
127  ((PNMFileTypeRegistry *)this)->sort_preferences();
128  }
129  return _types.size();
130 }
131 
132 /**
133  * Returns the nth type registered.
134  */
136 get_type(int n) const {
137  nassertr(n >= 0 && n < (int)_types.size(), nullptr);
138  return _types[n];
139 }
140 
141 /**
142  * Tries to determine what the PNMFileType is likely to be for a particular
143  * image file based on its extension. Returns a suitable PNMFileType pointer,
144  * or NULL if no type can be determined.
145  */
147 get_type_from_extension(const string &filename) const {
148  if (_requires_sort) {
149  ((PNMFileTypeRegistry *)this)->sort_preferences();
150  }
151 
152  // Extract the extension from the filename; if there is no dot, use the
153  // whole filename as the extension. This allows us to pass in just a
154  // dotless extension name in lieu of a filename.
155 
156  string extension;
157  size_t dot = filename.rfind('.');
158 
159  if (dot == string::npos) {
160  extension = filename;
161  } else {
162  extension = filename.substr(dot + 1);
163  }
164 
165 #ifdef HAVE_ZLIB
166  if (extension == "pz" || extension == "gz") {
167  // If the extension is .pz, then we've got a Panda-compressed image file.
168  // Back up some more and get the extension before that.
169  size_t prev_dot = filename.rfind('.', dot - 1);
170  if (prev_dot == string::npos) {
171  extension = filename.substr(0, dot);
172  } else {
173  extension = filename.substr(prev_dot + 1, dot - prev_dot - 1);
174  }
175  }
176 #endif // HAVE_ZLIB
177 
178  if (extension.find('/') != string::npos) {
179  // If we picked the whole filename and it contains slashes, or if the
180  // rightmost dot wasn't in the basename of the filename, then it's
181  // actually a filename without an extension.
182  extension = "";
183  }
184 
185  Extensions::const_iterator ei;
186  ei = _extensions.find(extension);
187  if (ei == _extensions.end() || (*ei).second.empty()) {
188  // Nothing matches that string. Try again with a downcased string in case
189  // we got an all-uppercase filename (most of our extensions are
190  // downcased).
191  ei = _extensions.find(downcase(extension));
192 
193  if (ei == _extensions.end() || (*ei).second.empty()) {
194  // Nothing matches that string.
195  return nullptr;
196  }
197  }
198 
199  // Return the first file type associated with the given extension.
200  return (*ei).second.front();
201 }
202 
203 /**
204  * Tries to determine what the PNMFileType is likely to be for a particular
205  * image file based on its magic number, the first two bytes read from the
206  * file. Returns a suitable PNMFileType pointer, or NULL if no type can be
207  * determined.
208  */
210 get_type_from_magic_number(const string &magic_number) const {
211  if (_requires_sort) {
212  ((PNMFileTypeRegistry *)this)->sort_preferences();
213  }
214 
215  Types::const_iterator ti;
216  for (ti = _types.begin(); ti != _types.end(); ++ti) {
217  PNMFileType *type = (*ti);
218  if (type->has_magic_number() &&
219  type->matches_magic_number(magic_number)) {
220  return type;
221  }
222  }
223 
224  return nullptr;
225 }
226 
227 /**
228  * Returns the PNMFileType instance stored in the registry for the given
229  * TypeHandle, e.g. as retrieved by a previous call to get_type() on the type
230  * instance.
231  */
234  Handles::const_iterator hi;
235  hi = _handles.find(handle);
236  if (hi != _handles.end()) {
237  return (*hi).second;
238  }
239 
240  return nullptr;
241 }
242 
243 /**
244  * Writes a list of supported image file types to the indicated output stream,
245  * one per line.
246  */
248 write(std::ostream &out, int indent_level) const {
249  if (_types.empty()) {
250  indent(out, indent_level) << "(No image types are known).\n";
251  } else {
252  Types::const_iterator ti;
253  for (ti = _types.begin(); ti != _types.end(); ++ti) {
254  PNMFileType *type = (*ti);
255  string name = type->get_name();
256  indent(out, indent_level) << name;
257  indent(out, std::max(30 - (int)name.length(), 0)) << " ";
258 
259  int num_extensions = type->get_num_extensions();
260  if (num_extensions == 1) {
261  out << "." << type->get_extension(0);
262  } else if (num_extensions > 1) {
263  out << "." << type->get_extension(0);
264  for (int i = 1; i < num_extensions; i++) {
265  out << ", ." << type->get_extension(i);
266  }
267  }
268  out << "\n";
269  }
270  }
271 }
272 
273 /**
274  * Returns a pointer to the global PNMFileTypeRegistry object.
275  */
278  if (_global_ptr == nullptr) {
279  _global_ptr = new PNMFileTypeRegistry;
280  }
281  return _global_ptr;
282 }
283 
284 /**
285  * Sorts the PNMFileType pointers in order according to user-specified
286  * preferences in the config file. This allows us to choose a particular
287  * PNMFileType over another for particular extensions when multiple file types
288  * map to the same extension, or for file types that have no magic number.
289  */
290 void PNMFileTypeRegistry::
291 sort_preferences() {
292  // So, we don't do anything here yet. One day we will.
293 
294  _requires_sort = false;
295 }
PNMFileType * get_type_from_magic_number(const std::string &magic_number) const
Tries to determine what the PNMFileType is likely to be for a particular image file based on its magi...
void write(std::ostream &out, int indent_level=0) const
Writes a list of supported image file types to the indicated output stream, one per line.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This is the base class of a family of classes that represent particular image file types that PNMImag...
Definition: pnmFileType.h:32
string downcase(const string &s)
Returns the input string with all uppercase letters converted to lowercase.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
static PNMFileTypeRegistry * get_global_ptr()
Returns a pointer to the global PNMFileTypeRegistry object.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
std::ostream & indent(std::ostream &out, int indent_level)
A handy function for doing text formatting.
Definition: indent.cxx:20
PNMFileType * get_type_by_handle(TypeHandle handle) const
Returns the PNMFileType instance stored in the registry for the given TypeHandle, e....
get_extension
Returns the nth possible filename extension associated with this particular file type,...
Definition: pnmFileType.h:44
PNMFileType * get_type_from_extension(const std::string &filename) const
Tries to determine what the PNMFileType is likely to be for a particular image file based on its exte...
virtual bool matches_magic_number(const std::string &magic_number) const
Returns true if the indicated "magic number" byte stream (the initial few bytes read from the file) m...
Definition: pnmFileType.cxx:86
This class maintains the set of all known PNMFileTypes in the universe.
void unregister_type(PNMFileType *type)
Removes a PNMFileType previously passed to register_type.
virtual bool has_magic_number() const
Returns true if this particular file type uses a magic number to identify it, false otherwise.
Definition: pnmFileType.cxx:76
This is our own Panda specialization on the default STL set.
Definition: pset.h:49
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
get_num_extensions
Returns the number of different possible filename extensions associated with this particular file typ...
Definition: pnmFileType.h:44
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void register_type(PNMFileType *type)
Defines a new PNMFileType in the universe.
get_type
Returns the nth type registered.