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  */
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  */
233 get_type_by_handle(TypeHandle handle) const {
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  */
277 get_global_ptr() {
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 }
This class maintains the set of all known PNMFileTypes in the universe.
get_num_types
Returns the total number of types registered.
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...
PNMFileType * get_type_by_handle(TypeHandle handle) const
Returns the PNMFileType instance stored in the registry for the given TypeHandle, e....
static PNMFileTypeRegistry * get_global_ptr()
Returns a pointer to the global PNMFileTypeRegistry object.
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.
get_type
Returns the nth type registered.
void unregister_type(PNMFileType *type)
Removes a PNMFileType previously passed to register_type.
void register_type(PNMFileType *type)
Defines a new PNMFileType in the universe.
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...
This is the base class of a family of classes that represent particular image file types that PNMImag...
Definition: pnmFileType.h:32
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
get_num_extensions
Returns the number of different possible filename extensions associated with this particular file typ...
Definition: pnmFileType.h:44
get_extension
Returns the nth possible filename extension associated with this particular file type,...
Definition: pnmFileType.h:44
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
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
This is our own Panda specialization on the default STL set.
Definition: pset.h:49
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
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
string downcase(const string &s)
Returns the input string with all uppercase letters converted to lowercase.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.