HepMC3 event record library
ReaderFactory.h
1 // -*- C++ -*-
2 //
3 // This file is part of HepMC
4 // Copyright (C) 2014-2021 The HepMC collaboration (see AUTHORS for details)
5 //
6 #ifndef HEPMC3_READERFACTORY_H
7 #define HEPMC3_READERFACTORY_H
8 
9 #include <memory>
10 #include <string>
11 #include <sys/stat.h>
12 #include <string.h>
13 
14 #include "HepMC3/ReaderAscii.h"
16 #include "HepMC3/ReaderHEPEVT.h"
17 #include "HepMC3/ReaderLHEF.h"
18 #include "HepMC3/ReaderPlugin.h"
19 #include "HepMC3/CompressedIO.h"
20 
21 namespace HepMC3 {
22 
23 
24 std::shared_ptr<Reader> deduce_reader(std::istream &stream);
25 
26 std::shared_ptr<Reader> deduce_reader(std::shared_ptr<std::istream> stream);
27 
28 /**
29  * @brief This function deduces the type of input file based on the name/URL
30  * and its content, and will return an appropriate Reader object
31  *
32  * @todo Too big for inlining: move into a .cc implementation file?
33  * @todo Need a DEBUG verbosity flag
34  */
35 std::shared_ptr<Reader> deduce_reader(const std::string &filename)
36 {
37  std::string libHepMC3rootIO = "libHepMC3rootIO.so.3";
38 #if defined(__darwin__) || defined(__APPLE__)
39  libHepMC3rootIO = "libHepMC3rootIO.dylib";
40 #endif
41 #if (defined(WIN32) || defined(_WIN32) || defined(__WIN32)) && !defined(__CYGWIN__)
42  libHepMC3rootIO = "HepMC3rootIO.dll";
43 #endif
44  bool remote = false;
45  bool pipe = false;
46  if (filename.find("http://") != std::string::npos) remote = true;
47  if (filename.find("https://") != std::string::npos) remote = true;
48  if (filename.find("root://") != std::string::npos) remote = true;
49  if (filename.find("gsidcap://") != std::string::npos) remote = true;
50 
51  std::vector<std::string> head;
52  if (!remote)
53  {
54  struct stat buffer;
55 #if (defined(WIN32) || defined(_WIN32) || defined(__WIN32)) && !defined(__CYGWIN__)
56  if (!(stat (filename.c_str(), &buffer) == 0))
57 #else
58  if (!(stat (filename.c_str(), &buffer) == 0 && (S_ISFIFO(buffer.st_mode) || S_ISREG(buffer.st_mode) || S_ISLNK(buffer.st_mode))))
59 #endif
60  {
61  HEPMC3_ERROR("deduce_reader: file " << filename << " does not exist or is not a regular file/FIFO/link");
62  return std::shared_ptr<Reader> (nullptr);
63  }
64 
65  std::ifstream* file= new std::ifstream(filename);
66  if (!file)
67  {
68  HEPMC3_ERROR("deduce_reader could not open file for testing HepMC version: " << filename);
69  return std::shared_ptr<Reader>(nullptr);
70  }
71  if (!file->is_open()) {
72  HEPMC3_ERROR("deduce_reader could not open file for testing HepMC version: " << filename);
73  file->close();
74  return std::shared_ptr<Reader>(nullptr);
75  }
76 
77 #if defined(__linux__) || defined(__darwin__)|| defined(__APPLE__) || defined(__FreeBSD__) || defined(__sun)
78  pipe = S_ISFIFO(buffer.st_mode);
79  if (pipe) {
80  HEPMC3_DEBUG(0, "deduce_reader: the file " << filename << " is a pipe");
81  return deduce_reader(*file);
82  }
83 #endif
84 
85  std::string line;
86  size_t nonempty = 0;
87  while (std::getline(*file, line) && nonempty < 3) {
88  if (line.empty()) continue;
89  nonempty++;
90  head.push_back(line);
91  }
92  file->close();
93  delete file;
94  }
95  // Assure there are at least two elements in the vector:
96  head.push_back("");
97  head.push_back("");
98  HEPMC3_DEBUG(0, "deduce_reader: Attempt ReaderRootTree for " << filename);
99  if ( strncmp(head.at(0).c_str(), "root", 4) == 0 || remote)
100  return std::make_shared<ReaderPlugin>(filename,libHepMC3rootIO,std::string("newReaderRootTreefile"));
101  if (!remote)
102  {
103 #if HEPMC3_USE_COMPRESSION
104  HEPMC3_DEBUG(0, "Attempt ReaderGZ for " << filename);
105  char buf[6];
106  snprintf(buf,6,"%s",head.at(0).c_str());
107  Compression det = detect_compression_type(buf, buf + 6);
108  if ( det != Compression::plaintext ) {
109  HEPMC3_DEBUG(0, "Detected supported compression " << std::to_string(det));
110  return deduce_reader(std::shared_ptr< std::istream >(new ifstream(filename.c_str())));
111  }
112 #endif
113  HEPMC3_DEBUG(0, "Attempt ReaderAscii for " << filename);
114  if ( strncmp(head.at(0).c_str(),"HepMC::Version",14) == 0 && strncmp(head.at(1).c_str(), "HepMC::Asciiv3", 14) == 0 )
115  return std::shared_ptr<Reader>((Reader*) ( new ReaderAscii(filename)));
116  HEPMC3_DEBUG(0, "Attempt ReaderAsciiHepMC2 for " << filename);
117  if ( strncmp(head.at(0).c_str(),"HepMC::Version",14) == 0 && strncmp(head.at(1).c_str(), "HepMC::IO_GenEvent", 18) == 0 )
118  return std::shared_ptr<Reader>((Reader*) ( new ReaderAsciiHepMC2(filename)));
119  HEPMC3_DEBUG(0, "Attempt ReaderLHEF for " << filename);
120  if ( strncmp(head.at(0).c_str(), "<LesHouchesEvents", 17) == 0)
121  return std::shared_ptr<Reader>((Reader*) ( new ReaderLHEF(filename)));
122  HEPMC3_DEBUG(0, "Attempt ReaderHEPEVT for " << filename);
123  std::stringstream st_e(head.at(0).c_str());
124  char attr = ' ';
125  bool HEPEVT = true;
126  int m_i,m_p;
127  while (true)
128  {
129  if (!(st_e >> attr)) {
130  HEPEVT=false;
131  break;
132  }
133  if (attr == ' ') continue;
134  if (attr != 'E') {
135  HEPEVT = false;
136  break;
137  }
138  HEPEVT=static_cast<bool>(st_e >> m_i >> m_p);
139  break;
140  }
141  if (HEPEVT) return std::shared_ptr<Reader>((Reader*) ( new ReaderHEPEVT(filename)));
142  }
143  HEPMC3_DEBUG(0, "deduce_reader: all attempts failed for " << filename);
144  return std::shared_ptr<Reader>(nullptr);
145 }
146 
147 
148 /** @brief This function will deduce the type of input stream based on its content and will return appropriate Reader*/
149 std::shared_ptr<Reader> deduce_reader(std::istream &stream)
150 {
151  std::vector<std::string> head;
152  head.push_back("");
153  size_t back = 0;
154  size_t backnonempty = 0;
155  while ( (back < 200 && backnonempty < 100) && stream) {
156  char c = stream.get();
157  back++;
158  if (c == '\n') {
159  if (head.back().length() != 0) head.push_back("");
160  } else {
161  head.back() += c;
162  backnonempty++;
163  }
164  }
165  if (!stream)
166  {
167  HEPMC3_WARNING("Input stream is too short or invalid.");
168  return std::shared_ptr<Reader>(nullptr);
169  }
170 
171  for (size_t i = 0; i < back; i++) stream.unget();
172 
173  if ( strncmp(head.at(0).c_str(), "HepMC::Version", 14) == 0 && strncmp(head.at(1).c_str(), "HepMC::Asciiv3", 14) == 0 )
174  {
175  HEPMC3_DEBUG(0, "Attempt ReaderAscii");
176  return std::shared_ptr<Reader>((Reader*) ( new ReaderAscii(stream)));
177  }
178 
179  if ( strncmp(head.at(0).c_str(), "HepMC::Version", 14) == 0 && strncmp(head.at(1).c_str(), "HepMC::IO_GenEvent", 18) == 0 )
180  {
181  HEPMC3_DEBUG(0, "Attempt ReaderAsciiHepMC2");
182  return std::shared_ptr<Reader>((Reader*) ( new ReaderAsciiHepMC2(stream)));
183  }
184 
185  if ( strncmp(head.at(0).c_str(), "<LesHouchesEvents", 17) == 0)
186  {
187  HEPMC3_DEBUG(0, "Attempt ReaderLHEF");
188  return std::shared_ptr<Reader>((Reader*) ( new ReaderLHEF(stream)));
189  }
190  HEPMC3_DEBUG(0, "Attempt ReaderHEPEVT");
191  std::stringstream st_e(head.at(0).c_str());
192  char attr = ' ';
193  bool HEPEVT = true;
194  int m_i, m_p;
195  while (true)
196  {
197  if (!(st_e >> attr)) {
198  HEPEVT = false;
199  break;
200  }
201  if (attr == ' ') continue;
202  if (attr != 'E') {
203  HEPEVT = false;
204  break;
205  }
206  HEPEVT = static_cast<bool>(st_e >> m_i >> m_p);
207  break;
208  }
209  if (HEPEVT) return std::shared_ptr<Reader>((Reader*) ( new ReaderHEPEVT(stream)));
210  HEPMC3_DEBUG(0, "deduce_reader: all attempts failed");
211  return std::shared_ptr<Reader>(nullptr);
212 }
213 /** @brief This function will deduce the type of input stream based on its content and will return appropriate Reader*/
214 std::shared_ptr<Reader> deduce_reader(std::shared_ptr<std::istream> stream)
215 {
216  std::vector<std::string> head;
217  head.push_back("");
218  size_t back = 0;
219  size_t backnonempty = 0;
220  while ( (back < 200 && backnonempty < 100) && stream) {
221  char c = stream->get();
222  back++;
223  if (c == '\n') {
224  if (head.back().length() != 0) head.push_back("");
225  } else {
226  head.back() += c;
227  backnonempty++;
228  }
229  }
230  if (!stream)
231  {
232  HEPMC3_WARNING("Input stream is too short or invalid.");
233  return std::shared_ptr<Reader>(nullptr);
234  }
235 
236  for (size_t i = 0; i < back; i++) stream->unget();
237 
238  if ( strncmp(head.at(0).c_str(), "HepMC::Version", 14) == 0 && strncmp(head.at(1).c_str(), "HepMC::Asciiv3", 14) == 0 )
239  {
240  HEPMC3_DEBUG(0, "Attempt ReaderAscii");
241  return std::shared_ptr<Reader>((Reader*) ( new ReaderAscii(stream)));
242  }
243 
244  if ( strncmp(head.at(0).c_str(), "HepMC::Version",14) == 0 && strncmp(head.at(1).c_str(), "HepMC::IO_GenEvent", 18) == 0 )
245  {
246  HEPMC3_DEBUG(0, "Attempt ReaderAsciiHepMC2");
247  return std::shared_ptr<Reader>((Reader*) ( new ReaderAsciiHepMC2(stream)));
248  }
249 
250  if ( strncmp(head.at(0).c_str(), "<LesHouchesEvents", 17) == 0)
251  {
252  HEPMC3_DEBUG(0, "Attempt ReaderLHEF");
253  return std::shared_ptr<Reader>((Reader*) ( new ReaderLHEF(stream)));
254  }
255  HEPMC3_DEBUG(0, "Attempt ReaderHEPEVT");
256  std::stringstream st_e(head.at(0).c_str());
257  char attr = ' ';
258  bool HEPEVT = true;
259  int m_i,m_p;
260  while (true)
261  {
262  if (!(st_e >> attr)) {
263  HEPEVT = false;
264  break;
265  }
266  if (attr == ' ') continue;
267  if (attr != 'E') {
268  HEPEVT = false;
269  break;
270  }
271  HEPEVT = static_cast<bool>(st_e >> m_i >> m_p);
272  break;
273  }
274  if (HEPEVT) return std::shared_ptr<Reader>((Reader*) ( new ReaderHEPEVT(stream)));
275  HEPMC3_DEBUG(0, "deduce_reader: all attempts failed");
276  return std::shared_ptr<Reader>(nullptr);
277 }
278 }
279 #endif
GenEvent I/O parsing and serialization for LHEF files.
Definition: ReaderLHEF.h:34
HepMC3 main namespace.
Definition of class ReaderHEPEVT.
#define HEPMC3_WARNING(MESSAGE)
Macro for printing HEPMC3_HEPMC3_WARNING messages.
Definition: Errors.h:27
GenEvent I/O parsing for structured text files.
Definition: ReaderAscii.h:29
GenEvent I/O parsing and serialization for HEPEVT files.
Definition: ReaderHEPEVT.h:32
#define HEPMC3_DEBUG(LEVEL, MESSAGE)
Macro for printing debug messages with appropriate debug level.
Definition: Errors.h:33
std::shared_ptr< Reader > deduce_reader(std::istream &stream)
This function will deduce the type of input stream based on its content and will return appropriate R...
Parser for HepMC2 I/O files.
Definition of class ReaderAsciiHepMC2.
Definition of class ReaderAscii.
Fortran common block HEPEVT.
Definition of class ReaderPlugin.
#define HEPMC3_ERROR(MESSAGE)
Macro for printing error messages.
Definition: Errors.h:24
Base class for all I/O readers.
Definition: Reader.h:25
Definition of class ReaderLHEF.