Panda3D
Loading...
Searching...
No Matches
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
24using std::string;
25
26PNMFileTypeRegistry *PNMFileTypeRegistry::_global_ptr;
27
28/**
29 *
30 */
31PNMFileTypeRegistry::
32PNMFileTypeRegistry() {
33 _requires_sort = false;
34}
35
36/**
37 *
38 */
39PNMFileTypeRegistry::
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 */
125get_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 */
136get_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 */
147get_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 */
210get_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 */
233get_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 */
248write(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 */
290void PNMFileTypeRegistry::
291sort_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.
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...
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.