A library for working with phylogenetic and population genetic data.
v0.32.0
gzip.cpp
Go to the documentation of this file.
1 /*
2  Genesis - A toolkit for working with phylogenetic data.
3  Copyright (C) 2014-2023 Lucas Czech
4 
5  This program is free software: you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation, either version 3 of the License, or
8  (at your option) any later version.
9 
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  GNU General Public License for more details.
14 
15  You should have received a copy of the GNU General Public License
16  along with this program. If not, see <http://www.gnu.org/licenses/>.
17 
18  Contact:
19  Lucas Czech <lczech@carnegiescience.edu>
20  Department of Plant Biology, Carnegie Institution For Science
21  260 Panama Street, Stanford, CA 94305, USA
22 */
23 
32 
35 
36 #include <cassert>
37 #include <fstream>
38 #include <stdexcept>
39 
40 #ifdef GENESIS_ZLIB
41 
42 # include "zlib.h"
43 
44 # if defined(MSDOS) || defined(OS2) || defined(WIN32) || defined(__CYGWIN__)
45 # include <fcntl.h>
46 # include <io.h>
47 # endif
48 
49 #endif // GENESIS_ZLIB
50 
51 namespace genesis {
52 namespace utils {
53 
54 // ================================================================================================
55 // General gzip/zlib Functions
56 // ================================================================================================
57 
58 bool is_gzip_compressed_file( std::string const& file_name )
59 {
60  // Check if the file extension hints at gzip.
61  auto const ext = file_extension( file_name );
62  bool const ext_gz = ( ext == "gz" || ext == "gzip" );
63 
64  // Open the file in binary mode.
65  std::ifstream infile;
66  infile.open( file_name, std::ifstream::in | std::ifstream::binary );
67  if( !infile.good() ) {
68  return false;
69  // throw std::runtime_error( "Cannot read from file '" + file_name + "'." );
70  }
71 
72  // Get the first two characters. If this fails, the file is too short, so it is not a gzip file.
73  unsigned char buffer[2];
74  infile.read( reinterpret_cast<char*>( &buffer ), 2 );
75  if( !infile.good() ) {
76  return false;
77  }
78  infile.close();
79 
80  // Check if the file starts with the magic number of gz files.
81  bool const magic = ( buffer[0] == 0x1f ) && ( buffer[1] == 0x8b );
82 
83  // If extension and magic number agree, we have a clear result.
84  // Otherwise, issue a warning, and return the magic bit, because this is what we trust more.
85  if( ext_gz && magic ) {
86  return true;
87  } else if( ! ext_gz && ! magic ) {
88  return false;
89  } else if( ext_gz && ! magic ) {
90  LOG_WARN << "File name '" << file_name << "' ends in '.gz', but the file does not seem "
91  << "to contain gzip content.";
92  } else if( ! ext_gz && magic ) {
93  LOG_WARN << "File name '" << file_name << "' does not end in '.gz', but the file seems "
94  << "to contain gzip content.";
95  } else {
96  // We have checked every compbination already.
97  assert( false );
98  }
99  return magic;
100 }
101 
102 // ================================================================================================
103 // Gzip Exception Class
104 // ================================================================================================
105 
106 #ifdef GENESIS_ZLIB
107 
108 GzipError::GzipError( std::string const& z_stream_message, int error_code )
109  : IOError("")
110 {
111  // Need to have this method in the cpp file, so that we do not expose the zlib header
112  // to the header file, which would include all its symbols to whichever class uses our headers...
113 
114  message_ = "zlib: ";
115  switch( error_code )
116  {
117  case Z_STREAM_ERROR:
118  message_ += "Invalid compression level. [Z_STREAM_ERROR: ";
119  break;
120  case Z_DATA_ERROR:
121  message_ += "Invalid or incomplete deflate data. [Z_DATA_ERROR: ";
122  break;
123  case Z_MEM_ERROR:
124  message_ += "Out of memory. [Z_MEM_ERROR: ";
125  break;
126  case Z_VERSION_ERROR:
127  message_ += "Version mismatch! [Z_VERSION_ERROR: ";
128  break;
129  case Z_BUF_ERROR:
130  message_ += "Buffer error. [Z_BUF_ERROR: ";
131  break;
132  case Z_ERRNO:
133  message_ += "Error while reading zlib/gzip input. [Z_ERRNO: ";
134  break;
135  default:
136  message_ += "Unknown error. [" + std::to_string(error_code) + ": ";
137  break;
138  }
139  message_ += z_stream_message + "]";
140 }
141 
142 #else // GENESIS_ZLIB
143 
144 GzipError::GzipError( std::string const&, int )
145  : IOError("")
146 {
147  message_ = "zlib: Genesis was not compiled with zlib support.";
148 }
149 
150 #endif // GENESIS_ZLIB
151 
152 } // namespace utils
153 } // namespace genesis
genesis::utils::GzipError::GzipError
GzipError(std::string const &z_stream_message, int error_code)
Definition: gzip.cpp:108
fs.hpp
Provides functions for accessing the file system.
genesis::utils::Exception::message_
std::string message_
Definition: exception.hpp:68
gzip.hpp
genesis::population::to_string
std::string to_string(GenomeLocus const &locus)
Definition: function/genome_locus.hpp:52
LOG_WARN
#define LOG_WARN
Log a warning. See genesis::utils::LoggingLevel.
Definition: logging.hpp:97
logging.hpp
Provides easy and fast logging functionality.
genesis::utils::is_gzip_compressed_file
bool is_gzip_compressed_file(std::string const &file_name)
Return whether a given file is gzip-compressed.
Definition: gzip.cpp:58
genesis::utils::IOError
Exception class for general input/output errors.
Definition: exception.hpp:79
genesis
Container namespace for all symbols of genesis in order to keep them separate when used as a library.
Definition: placement/formats/edge_color.cpp:42
genesis::utils::file_extension
std::string file_extension(std::string const &filename)
Return the extension name of a file.
Definition: fs.cpp:821