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