GammaLib 2.0.0
Loading...
Searching...
No Matches
GFilename.cpp
Go to the documentation of this file.
1/***************************************************************************
2 * GFilename.cpp - Filename class *
3 * ----------------------------------------------------------------------- *
4 * copyright (C) 2015-2017 by Juergen Knoedlseder *
5 * ----------------------------------------------------------------------- *
6 * *
7 * This program is free software: you can redistribute it and/or modify *
8 * it under the terms of the GNU General Public License as published by *
9 * the Free Software Foundation, either version 3 of the License, or *
10 * (at your option) any later version. *
11 * *
12 * This program is distributed in the hope that it will be useful, *
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15 * GNU General Public License for more details. *
16 * *
17 * You should have received a copy of the GNU General Public License *
18 * along with this program. If not, see <http://www.gnu.org/licenses/>. *
19 * *
20 ***************************************************************************/
21/**
22 * @file GFilename.cpp
23 * @brief Filename class interface implementation
24 * @author Juergen Knoedlseder
25 */
26
27/* __ Includes ___________________________________________________________ */
28#ifdef HAVE_CONFIG_H
29#include <config.h>
30#endif
31#if defined(HAVE_LIBCFITSIO)
32#if defined(HAVE_CFITSIO_FITSIO_H)
33#include <cfitsio/fitsio.h>
34#elif defined(HAVE_LIBCFITSIO0_FITSIO_H)
35#include <libcfitsio0/fitsio.h>
36#else
37#include <fitsio.h>
38#endif
39#endif
40#include <sys/stat.h> // for stat structure and S_ISREG
41#include <cstdio> // for std::remove()
42#include "GFilename.hpp"
43#include "GTools.hpp"
44#include "GException.hpp"
45
46/* __ Method name definitions ____________________________________________ */
47#define G_SET_FILENAME "GFilename::set_filename(std::string&)"
48
49/* __ Macros _____________________________________________________________ */
50
51/* __ Coding definitions _________________________________________________ */
52
53/* __ Debug definitions __________________________________________________ */
54
55
56/*==========================================================================
57 = =
58 = Constructors/destructors =
59 = =
60 ==========================================================================*/
61
62/***********************************************************************//**
63 * @brief Void constructor
64 ***************************************************************************/
66{
67 // Initialise members
69
70 // Return
71 return;
72}
73
74
75/***********************************************************************//**
76 * @brief Filename constructor
77 *
78 * @param[in] filename File name.
79 *
80 * Constructs GFilename object by assigning a @p filename.
81 ***************************************************************************/
82GFilename::GFilename(const std::string& filename)
83{
84 // Initialise members
86
87 // Set filename
88 set_filename(filename);
89
90 // Return
91 return;
92}
93
94
95/***********************************************************************//**
96 * @brief Filename constructor
97 *
98 * @param[in] filename File name.
99 *
100 * Constructs GFilename object by assigning a @p filename.
101 ***************************************************************************/
102GFilename::GFilename(const char* filename)
103{
104 // Initialise members
105 init_members();
106
107 // Set filename
108 set_filename(std::string(filename));
109
110 // Return
111 return;
112}
113
114
115/***********************************************************************//**
116 * @brief Copy constructor
117 *
118 * @param[in] filename File name.
119 ***************************************************************************/
121{
122 // Initialise members
123 init_members();
124
125 // Copy members
126 copy_members(filename);
127
128 // Return
129 return;
130}
131
132
133/***********************************************************************//**
134 * @brief Destructor
135 ***************************************************************************/
137{
138 // Free members
139 free_members();
140
141 // Return
142 return;
143}
144
145
146/*==========================================================================
147 = =
148 = Operators =
149 = =
150 ==========================================================================*/
151
152/***********************************************************************//**
153 * @brief Assignment operator
154 *
155 * @param[in] filename File name.
156 * @return File name.
157 ***************************************************************************/
159{
160 // Execute only if object is not identical
161 if (this != &filename) {
162
163 // Free members
164 free_members();
165
166 // Initialise members
167 init_members();
168
169 // Copy members
170 copy_members(filename);
171
172 } // endif: object was not identical
173
174 // Return
175 return *this;
176}
177
178
179/*==========================================================================
180 = =
181 = Public methods =
182 = =
183 ==========================================================================*/
184
185/***********************************************************************//**
186 * @brief Clear file name
187 ***************************************************************************/
189{
190 // Free class members
191 free_members();
192
193 // Initialise members
194 init_members();
195
196 // Return
197 return;
198}
199
200
201/***********************************************************************//**
202 * @brief Clone file name
203 *
204 * @return Pointer to deep copy of file name.
205 ***************************************************************************/
207{
208 // Clone object
209 return new GFilename(*this);
210}
211
212
213/***********************************************************************//**
214 * @brief Checks whether file exists
215 *
216 * @return True if file exists.
217 *
218 * Checks whether a file exists on disk. In case that the file is a FITS
219 * file, the method also checks whether a compressed version of the file
220 * (with a .gz, .Z, .z, or .zip extension) exists on disk (see is_fits()
221 * method).
222 ***************************************************************************/
223bool GFilename::exists(void) const
224{
225 // First check if file is a FITS file
226 bool exists = is_fits();
227
228 // If the file is not a FITS file, then check whether a file with the
229 // given name exists
230 if (!exists) {
231
232 // Allocate file information structure
233 struct stat info;
234
235 // Get file information structure
236 int ret = stat(url().c_str(), &info);
237
238 // If the file is a regular file then signal that it exists
239 if (ret == 0 && S_ISREG(info.st_mode)) {
240 exists = true;
241 }
242
243 } // endif: file was not a FITS file
244
245 // Return result
246 return (exists);
247}
248
249
250/***********************************************************************//**
251 * @brief Return file type
252 *
253 * @return File type.
254 *
255 * Returns the file type based on the file extension name. Possible file
256 * types are
257 *
258 * Type Extension names
259 * fits .fits / .fit
260 *
261 * For any other file types an empty string will be returned. Any compression
262 * extensions such as `.gz`, `.Z`, `.z` or `.zip` will be stripped.
263 ***************************************************************************/
264std::string GFilename::type(void) const
265{
266 // Initialise empty file type
267 std::string type = "";
268
269 // Initialise type with the name of the file
270 std::string file = m_file;
271
272 // Strip compression extensions
273 size_t start = file.rfind(".gz");
274 if (start != std::string::npos) {
275 file = file.substr(0, start);
276 }
277 start = file.rfind(".Z");
278 if (start != std::string::npos) {
279 file = file.substr(0, start);
280 }
281 start = file.rfind(".z");
282 if (start != std::string::npos) {
283 file = file.substr(0, start);
284 }
285 start = file.rfind(".zip");
286 if (start != std::string::npos) {
287 file = file.substr(0, start);
288 }
289
290 // Extract file type
291 start = file.rfind(".fits");
292 if (start != std::string::npos) {
293 type = "fits";
294 }
295 start = file.rfind(".fit");
296 if (start != std::string::npos) {
297 type = "fits";
298 }
299
300 // Return file type
301 return type;
302}
303
304
305/***********************************************************************//**
306 * @brief Checks whether file is a FITS file
307 *
308 * @return True if file is a FITS file.
309 *
310 * Test if the file or a compressed version of the file (with a .gz, .Z, .z,
311 * or .zip extension) is a FITS file. This method is thread safe.
312 ***************************************************************************/
313bool GFilename::is_fits(void) const
314{
315 // Initialise result
316 bool is_fits = false;
317
318 // Check now for a FITS file. This works only if cfitsio is available.
319 // Put the code into a critical zone as it might be called from within
320 // a parallelized thread.
321 #if defined(HAVE_LIBCFITSIO)
322 #pragma omp critical(GFilename_is_fits)
323 {
324 int status = 0;
325 fitsfile* fptr = NULL;
326 status = ffopen(&fptr, url().c_str(), 0, &status);
327 if (status == 0) {
328 is_fits = true;
329 }
330 ffclos(fptr, &status);
331 }
332 #endif
333
334 // Return result
335 return (is_fits);
336}
337
338
339/***********************************************************************//**
340 * @brief Remove file from disk
341 *
342 * Removes file or a compressed version of the file (with a .gz, .Z, .z,
343 * or .zip extension) if it exists on disk.
344 ***************************************************************************/
345void GFilename::remove(void) const
346{
347 // Set compressed file name variants
348 GFilename name_gz = url()+".gz";
349 GFilename name_Z = url()+".Z";
350 GFilename name_z = url()+".z";
351 GFilename name_zip = url()+".zip";
352
353 // Remove file if one of the variants exists on disk
354 if (name_gz.exists()) {
355 std::remove(name_gz.url().c_str());
356 }
357 else if (name_Z.exists()) {
358 std::remove(name_Z.url().c_str());
359 }
360 else if (name_z.exists()) {
361 std::remove(name_z.url().c_str());
362 }
363 else if (name_zip.exists()) {
364 std::remove(name_zip.url().c_str());
365 }
366 else if (exists()) {
367 std::remove(url().c_str());
368 }
369
370 // Return
371 return;
372}
373
374
375/***********************************************************************//**
376 * @brief Return extension name
377 *
378 * @param[in] defaultname Default extension name (default: "").
379 * @return String containing extension name.
380 *
381 * Returns the extension name. If no extension name is given the name
382 * provided by the @p defaultname argument will be used. By default, the
383 * @p defaultname parameter is an empty string.
384 ***************************************************************************/
385std::string GFilename::extname(const std::string& defaultname) const
386{
387 // Set the extension name
388 std::string extname = m_extname;
389
390 // If no extension name is set, the use the default extension name
391 if (!has_extname()) {
392 extname = defaultname;
393 }
394
395 // Return extension name
396 return (extname);
397}
398
399
400/***********************************************************************//**
401 * @brief Return extension number
402 *
403 * @param[in] defaultno Default extension number (default: -11).
404 * @return Integer containing extension number.
405 *
406 * Returns the extension number. If no extension number is given the number
407 * provided by the @p defaultno argument will be used. By default, the
408 * @p defaultno parameter is set to -1.
409 ***************************************************************************/
410int GFilename::extno(const int& defaultno) const
411{
412 // Set the extension number
413 int extno = m_extno;
414
415 // If no extension number is set, the use the default extension number
416 if (!has_extno()) {
417 extno = defaultno;
418 }
419
420 // Return extension number
421 return (extno);
422}
423
424
425/***********************************************************************//**
426 * @brief Return extension version number
427 *
428 * @param[in] defaultver Default extension version number (default: 0).
429 * @return Integer containing extension version number.
430 *
431 * Returns the extension version number. If no extension version number is
432 * given the number provided by the @p defaultver argument will be used. By
433 * default, the @p defaultextver parameter is set to 0.
434 ***************************************************************************/
435int GFilename::extver(const int& defaultver) const
436{
437 // Set the extension version
438 int extver = m_extver;
439
440 // If no extension version is set, the use the default extension version
441 if (!has_extver()) {
442 extver = defaultver;
443 }
444
445 // Return extension version
446 return (extver);
447}
448
449
450/***********************************************************************//**
451 * @brief Print file name information
452 *
453 * @param[in] chatter Chattiness (default: NORMAL).
454 * @return String containing file name information.
455 ***************************************************************************/
456std::string GFilename::print(const GChatter& chatter) const
457{
458 // Initialise result string
459 std::string result;
460
461 // Continue only if chatter is not silent
462 if (chatter != SILENT) {
463
464 // Append header
465 result.append("=== GFilename ===");
466
467 // Append filename
468 result.append("\n"+gammalib::parformat("File name"));
469 result.append(m_filename);
470
471 // Append URL
472 result.append("\n"+gammalib::parformat("URL"));
473 result.append(m_url);
474
475 // Append protocol
476 result.append("\n"+gammalib::parformat("Protocol"));
477 result.append(m_protocol);
478
479 // Append access path
480 result.append("\n"+gammalib::parformat("Access path"));
481 result.append(m_path);
482
483 // Append file name
484 result.append("\n"+gammalib::parformat("File"));
485 result.append(m_file);
486
487 // Append extension name
488 result.append("\n"+gammalib::parformat("Extension name"));
489 if (has_extname()) {
490 result.append(m_extname);
491 }
492 else {
493 result.append("Not provided");
494 }
495
496 // Append extension number
497 result.append("\n"+gammalib::parformat("Extension number"));
498 if (has_extno()) {
499 result.append(gammalib::str(m_extno));
500 }
501 else {
502 result.append("Not provided");
503 }
504
505 // Append extension version
506 result.append("\n"+gammalib::parformat("Extension version"));
507 if (has_extver()) {
508 result.append(gammalib::str(m_extver));
509 }
510 else {
511 result.append("Not provided");
512 }
513
514 // Append expression
515 result.append("\n"+gammalib::parformat("Selection expression"));
516 if (has_expression()) {
517 result.append(m_expression);
518 }
519 else {
520 result.append("Not provided");
521 }
522
523 } // endif: chatter was not silent
524
525 // Return result
526 return result;
527}
528
529
530/*==========================================================================
531 = =
532 = Private methods =
533 = =
534 ==========================================================================*/
535
536/***********************************************************************//**
537 * @brief Initialise class members
538 ***************************************************************************/
540{
541 // Initialise members
542 m_filename.clear();
543 m_url.clear();
544 m_protocol.clear();
545 m_path.clear();
546 m_file.clear();
547 m_extname.clear();
548 m_extno = -1;
549 m_extver = 0;
550 m_expression.clear();
551
552 // Return
553 return;
554}
555
556
557/***********************************************************************//**
558 * @brief Copy class members
559 *
560 * @param[in] filename File name.
561 ***************************************************************************/
563{
564 // Copy members
565 m_filename = filename.m_filename;
566 m_url = filename.m_url;
567 m_protocol = filename.m_protocol;
568 m_path = filename.m_path;
569 m_file = filename.m_file;
570 m_extname = filename.m_extname;
571 m_extno = filename.m_extno;
572 m_extver = filename.m_extver;
573 m_expression = filename.m_expression;
574
575 // Return
576 return;
577}
578
579
580/***********************************************************************//**
581 * @brief Delete class members
582 ***************************************************************************/
584{
585 // Return
586 return;
587}
588
589
590/***********************************************************************//**
591 * @brief Set file name
592 *
593 * @param[in] filename File name.
594 *
595 * @exception GException::invalid_argument
596 * Invalid file name specified.
597 *
598 * Sets all attributes of the object by parsing the file name. The file name
599 * can have one of the following formats:
600 *
601 * file.fits No extension
602 * file.fits[1] Extension number 1 (starting from 0)
603 * file.fits[EVENTS] EVENTS extension
604 * file.fits[EVENTS,2] Version 2 of the EVENTS extension
605 ***************************************************************************/
606void GFilename::set_filename(const std::string& filename)
607{
608 // Clear file name
609 clear();
610
611 // Strip any whitespace and store the full name
613
614 // Continue only if filename is not empty
615 if (!m_filename.empty()) {
616
617 // Check for [ symbol in filename
618 size_t start = m_filename.find_first_of("[");
619
620 // If we have an extension then separate filename into filename
621 // part and extension part and fill the information of th object
622 if (start != std::string::npos) {
623
624 // Check for ] symbol in filename
625 size_t stop = m_filename.find_first_of("]", start);
626
627 // If there is no ] symbol then throw an exception
628 if (stop == std::string::npos) {
629 std::string msg = "Missing ] symbol in file name \""+
630 m_filename+"\" extension. Please correct "
631 "the file name.";
633 }
634
635 // If ] is not the last character then check if an opening bracket is next
636 if (stop < m_filename.length()-1) {
637
638 // Get character
639 std::string character = gammalib::strip_whitespace(m_filename.substr(stop+1,1));
640
641 // If no bracket is coming, throw an exception
642 if (character != "[") {
643 std::string msg = "Non-bracket character \""+character+
644 "\" beyond ] symbol in file name \""+
645 m_filename+"\" expression. Please "
646 "correct the file name.";
648 }
649 }
650
651 // Extract extension name
652 std::string extname = gammalib::strip_whitespace(m_filename.substr(start+1, stop-start-1));
653
654 // Check if there is a , symbol that separates extension name
655 // and extension version
656 size_t sep = extname.find_first_of(",");
657
658 // If we have a separator, then extract the extension version
659 if (sep != std::string::npos) {
660
661 // Get extension version string
662 std::string extver = gammalib::strip_whitespace(extname.substr(sep+1, std::string::npos));
663
664 // If string is empty then throw an exception
665 if (extver.empty()) {
666 std::string msg = "No extension version found after , "
667 "symbol in file name \""+m_filename+
668 "\". Please correct the file name.";
670 }
671
672 // Extract extension version
674
675 // Throw an exception if the extension version is not
676 // positive
677 if (m_extver <= 0) {
678 std::string msg = "Non-positive extension version "
679 "encountered in file name \""+
680 m_filename+ "\". Please correct the "
681 "file name.";
683 }
684
685 // Update the extension name
687
688 } // endif: extension version provided
689
690 // If we have an empty extension name then throw an exception
691 if (extname.empty()) {
692 std::string msg = "An empty extension has been specified in "
693 "file name \""+m_filename+"\". Please "
694 "correct the file name.";
696 }
697
698 // If we have a purely numerical extension then convert the
699 // extension name into an extension number
700 if (extname.find_first_not_of("+-0123456789") == std::string::npos) {
701
702 // Extract extension number
704
705 // Throw an exception if the extension version is not
706 // positive
707 if (m_extno < 0) {
708 std::string msg = "Negative extension number encountered "
709 "in file name \""+m_filename+"\". "
710 "Please correct the file name.";
712 }
713
714 } // endif: extension number provided
715
716 // ... otherwise store the extension name
717 else {
718
719 // Store extension name
721
722 // Throw an exception if extension name is empty
723 if (m_extname.empty()) {
724 std::string msg = "Empty extension name encountered "
725 "in file name \""+m_filename+"\". "
726 "Please correct the file name.";
728 }
729
730 } // endelse: extension name provided
731
732 // Store the file name
734
735 // Check if there is an expression behind the extension name
736 size_t expr_start = m_filename.find_first_of("[", stop+1);
737
738 if (expr_start != std::string::npos) {
739
740 // Check for ] symbol in expression
741 size_t expr_stop = m_filename.find_first_of("]", expr_start);
742
743 // If there is no ] symbol then throw an exception
744 if (expr_stop == std::string::npos) {
745 std::string msg = "Missing ] symbol in file name \""+
746 m_filename+"\" expression. Please "
747 "correct the file name.";
749 }
750
751 // If ] is not the last character then throw an exception
752 if (expr_stop < m_filename.length()-1) {
753 std::string msg = "Characters beyond ] symbol in file "
754 "name \""+m_filename+"\" expression. "
755 "Please correct the file name.";
757 }
758
759 // Store expression
760 m_expression = gammalib::strip_whitespace(m_filename.substr(expr_start+1, expr_stop - expr_start-1));
761 }
762
763 } // endif: had extension
764
765 // ... otherwise simply set the filename
766 else {
768 }
769
770 // Extract access protocol
771 size_t proto_end = m_filename.find_first_of(":");
772 if (proto_end != std::string::npos) {
773 m_protocol = m_filename.substr(0, proto_end);
774 proto_end++;
775 }
776 else {
777 proto_end = 0;
778 }
779
780 // Set start and end of file name
781 size_t file_start = m_filename.find_last_of("/");
782 size_t file_end = (start == std::string::npos) ? m_filename.length() : start;
783
784 // If a "/" symbol was found then extract the path and file
785 if (file_start != std::string::npos) {
786
787 // Extract path
788 size_t path_start = m_filename.find_first_not_of("/", proto_end);
789 if (path_start != std::string::npos) {
790 if (path_start > 0) {
791 path_start--;
792 }
793 int length = file_start - path_start + 1;
794 if (length > 0) {
795 m_path = m_filename.substr(path_start, length);
796 }
797 }
798
799 // Extract file name
800 int length = file_end - file_start - 1;
801 if (length > 0) {
802 m_file = m_filename.substr(file_start+1, length);
803 }
804 }
805
806 // ... otherwise there is no path and we only extract the file
807 else {
808 int length = file_end - proto_end;
809 if (length > 0) {
810 m_file = m_filename.substr(proto_end, length);
811 }
812 }
813
814 } // endif: filename was not empty
815
816 // Return
817 return;
818}
Exception handler interface definition.
#define G_SET_FILENAME
Definition GFilename.cpp:47
Filename class interface definition.
Gammalib tools definition.
GChatter
Definition GTypemaps.hpp:33
@ SILENT
Definition GTypemaps.hpp:34
Filename class.
Definition GFilename.hpp:62
std::string print(const GChatter &chatter=NORMAL) const
Print file name information.
GFilename * clone(void) const
Clone file name.
GFilename & operator=(const GFilename &filename)
Assignment operator.
void copy_members(const GFilename &filename)
Copy class members.
int m_extver
Extension version (0: not set)
std::string m_path
Access path.
void free_members(void)
Delete class members.
std::string file(void) const
Return name of file.
int length(void) const
Return length of filename.
std::string m_file
Name of file.
bool has_expression(void) const
Signal if filename has an expression.
std::string type(void) const
Return file type.
bool has_extname(void) const
Signal if filename has an extension name.
bool is_fits(void) const
Checks whether file is a FITS file.
GFilename(void)
Void constructor.
Definition GFilename.cpp:65
void set_filename(const std::string &filename)
Set file name.
bool has_extno(void) const
Signal if filename has an extension number.
std::string m_url
File name (with stripped extension info)
std::string url(void) const
Return Uniform Resource Locator (URL)
void remove(void) const
Remove file from disk.
std::string extname(const std::string &defaultname="") const
Return extension name.
bool exists(void) const
Checks whether file exists.
std::string m_filename
Full file name.
int extno(const int &defaultno=-1) const
Return extension number.
int m_extno
Extension number (-1: not set)
std::string m_extname
Extension name ("": not set)
int extver(const int &defaultver=0) const
Return extension version number.
void init_members(void)
Initialise class members.
bool has_extver(void) const
Signal if filename has an extension version.
std::string m_protocol
Access protocol.
std::string m_expression
Selection expression ("": not set)
virtual ~GFilename(void)
Destructor.
void clear(void)
Clear file name.
std::string parformat(const std::string &s, const int &indent=0)
Convert string in parameter format.
Definition GTools.cpp:1143
std::string str(const unsigned short int &value)
Convert unsigned short integer value into string.
Definition GTools.cpp:489
int toint(const std::string &arg)
Convert string into integer value.
Definition GTools.cpp:821
std::string strip_whitespace(const std::string &arg)
Strip leading and trailing whitespace from string.
Definition GTools.cpp:80
std::string toupper(const std::string &s)
Convert string to upper case.
Definition GTools.cpp:941