HepMC3 event record library
ReaderFactory.h
1// -*- C++ -*-
2//
3// This file is part of HepMC
4// Copyright (C) 2014-2023 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
21namespace HepMC3 {
22
23
24std::shared_ptr<Reader> deduce_reader(std::istream &stream);
25
26std::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 */
35std::shared_ptr<Reader> deduce_reader(const std::string &filename)
36{
37 std::string libHepMC3rootIO = "libHepMC3rootIO.so.3";
38 std::string libHepMC3protobufIO = "libHepMC3protobufIO.so.3";
39#if defined(__darwin__) || defined(__APPLE__)
40 libHepMC3rootIO = "libHepMC3rootIO.dylib";
41 libHepMC3protobufIO = "libHepMC3protobufIO.dylib";
42#endif
43#if (defined(WIN32) || defined(_WIN32) || defined(__WIN32)) && !defined(__CYGWIN__)
44 libHepMC3protobufIO = "HepMC3protobufIO.dll";
45 libHepMC3rootIO = "HepMC3rootIO.dll";
46#endif
47
48 bool remote = false;
49 bool pipe = false;
50 if (filename.find("http://") != std::string::npos) remote = true;
51 if (filename.find("https://") != std::string::npos) remote = true;
52 if (filename.find("root://") != std::string::npos) remote = true;
53 if (filename.find("gsidcap://") != std::string::npos) remote = true;
54
55 std::vector<std::string> head;
56 if (!remote)
57 {
58 struct stat buffer;
59#if (defined(WIN32) || defined(_WIN32) || defined(__WIN32)) && !defined(__CYGWIN__)
60 if (!(stat (filename.c_str(), &buffer) == 0))
61#else
62 if (!(stat (filename.c_str(), &buffer) == 0 && (S_ISFIFO(buffer.st_mode) || S_ISREG(buffer.st_mode) || S_ISLNK(buffer.st_mode))))
63#endif
64 {
65 HEPMC3_ERROR("deduce_reader: file " << filename << " does not exist or is not a regular file/FIFO/link");
66 return std::shared_ptr<Reader> (nullptr);
67 }
68
69 std::shared_ptr< std::ifstream > file = std::make_shared< std::ifstream >(filename);
70 if (!file)
71 {
72 HEPMC3_ERROR("deduce_reader could not open file for testing HepMC version: " << filename);
73 return std::shared_ptr<Reader>(nullptr);
74 }
75 if (!file->is_open()) {
76 HEPMC3_ERROR("deduce_reader could not open file for testing HepMC version: " << filename);
77 file->close();
78 return std::shared_ptr<Reader>(nullptr);
79 }
80
81#if defined(__linux__) || defined(__darwin__)|| defined(__APPLE__) || defined(__FreeBSD__) || defined(__sun)
82 pipe = S_ISFIFO(buffer.st_mode);
83 if (pipe) {
84 HEPMC3_DEBUG(10, "deduce_reader: the file " << filename << " is a pipe");
85 return deduce_reader(file);
86 }
87#endif
88
89 std::string line;
90 size_t nonempty = 0;
91 while (std::getline( *(file.get()), line) && nonempty < 3) {
92 if (line.empty()) continue;
93 nonempty++;
94 head.push_back(line);
95 }
96 file->close();
97 }
98 // Assure there are at least two elements in the vector:
99 head.push_back("");
100 head.push_back("");
101 HEPMC3_DEBUG(10, "deduce_reader: Attempt ReaderRootTree for " << filename);
102 if ( strncmp(head.at(0).c_str(), "root", 4) == 0 || remote)
103 return std::make_shared<ReaderPlugin>(filename,libHepMC3rootIO,std::string("newReaderRootTreefile"));
104 if (!remote)
105 {
106 HEPMC3_DEBUG(10, "deduce_reader: Attempt ProtobufIO for " << filename);
107 if ( strncmp(head.at(0).c_str(),"hmpb",4) == 0 )
108 return std::make_shared<ReaderPlugin>(filename,libHepMC3protobufIO,std::string("newReaderprotobuffile"));
109#if HEPMC3_USE_COMPRESSION
110 HEPMC3_DEBUG(10, "Attempt ReaderGZ for " << filename);
111 char buf[6];
112 snprintf(buf,6,"%s",head.at(0).c_str());
113 Compression det = detect_compression_type(buf, buf + 6);
114 if ( det != Compression::plaintext ) {
115 HEPMC3_DEBUG(10, "Detected supported compression " << std::to_string(det));
116 return deduce_reader(std::shared_ptr< std::istream >(new ifstream(filename.c_str())));
117 }
118#endif
119 HEPMC3_DEBUG(10, "Attempt ReaderAscii for " << filename);
120 if ( strncmp(head.at(0).c_str(),"HepMC::Version",14) == 0 && strncmp(head.at(1).c_str(), "HepMC::Asciiv3", 14) == 0 )
121 return std::shared_ptr<Reader>((Reader*) ( new ReaderAscii(filename)));
122 HEPMC3_DEBUG(10, "Attempt ReaderAsciiHepMC2 for " << filename);
123 if ( strncmp(head.at(0).c_str(),"HepMC::Version",14) == 0 && strncmp(head.at(1).c_str(), "HepMC::IO_GenEvent", 18) == 0 )
124 return std::shared_ptr<Reader>((Reader*) ( new ReaderAsciiHepMC2(filename)));
125 HEPMC3_DEBUG(10, "Attempt ReaderLHEF for " << filename);
126 if ( strncmp(head.at(0).c_str(), "<LesHouchesEvents", 17) == 0)
127 return std::shared_ptr<Reader>((Reader*) ( new ReaderLHEF(filename)));
128 HEPMC3_DEBUG(10, "Attempt ReaderHEPEVT for " << filename);
129 std::stringstream st_e(head.at(0).c_str());
130 char attr = ' ';
131 bool HEPEVT = true;
132 int m_i,m_p;
133 while (true)
134 {
135 if (!(st_e >> attr)) {
136 HEPEVT=false;
137 break;
138 }
139 if (attr == ' ') continue;
140 if (attr != 'E') {
141 HEPEVT = false;
142 break;
143 }
144 HEPEVT=static_cast<bool>(st_e >> m_i >> m_p);
145 break;
146 }
147 if (HEPEVT) return std::shared_ptr<Reader>((Reader*) ( new ReaderHEPEVT(filename)));
148 }
149 HEPMC3_DEBUG(10, "deduce_reader: all attempts failed for " << filename);
150 return std::shared_ptr<Reader>(nullptr);
151}
152
153
154/** @brief This function will deduce the type of input stream based on its content and will return appropriate Reader*/
155std::shared_ptr<Reader> deduce_reader(std::istream &stream)
156{
157 const size_t raw_header_size = 100;
158 std::string raw_header(raw_header_size + 1,'\0');
159 auto fstream = dynamic_cast<std::ifstream*>(&stream);
160 if (fstream) {
161 fstream->read(&(raw_header[0]), raw_header_size);
162 } else {
163 stream.read(&(raw_header[0]), raw_header_size);
164 }
165 std::vector<std::string> head;
166 head.push_back("");
167 for ( size_t i = 0; i < raw_header_size; ++i) {
168 const char c = raw_header[i];
169 if (c == '\0') break;
170 if (c == '\n') {
171 if (head.back().length() != 0) {
172 head.push_back("");
173 }
174 } else {
175 head.back() += c;
176 }
177 }
178 head.push_back("");
179 if (fstream) {
180 for (size_t i = 0; i < raw_header_size; ++i) { static_cast<std::filebuf*>(fstream->rdbuf())->sungetc(); }
181 HEPMC3_DEBUG(10, "After sungetc() fstream->good()=" + std::to_string(fstream->good()));
182 } else {
183 for (size_t i = 0; i < raw_header_size; ++i) { stream.rdbuf()->sungetc(); }
184 HEPMC3_DEBUG(10, "After sungetc() stream.good()=" + std::to_string(stream.good()));
185 }
186 if (!stream)
187 {
188 HEPMC3_WARNING("Input stream is too short or invalid.");
189 return std::shared_ptr<Reader>(nullptr);
190 }
191
192 if ( strncmp(head.at(0).c_str(),"hmpb",4) == 0 )
193 {
194 std::string libHepMC3protobufIO = "libHepMC3protobufIO.so.3";
195#if defined(__darwin__) || defined(__APPLE__)
196 libHepMC3protobufIO = "libHepMC3protobufIO.dylib";
197#endif
198#if (defined(WIN32) || defined(_WIN32) || defined(__WIN32)) && !defined(__CYGWIN__)
199 libHepMC3protobufIO = "HepMC3protobufIO.dll";
200#endif
201
202 return std::make_shared<ReaderPlugin>(stream,libHepMC3protobufIO,std::string("newReaderprotobufstream"));
203 }
204
205 if ( strncmp(head.at(0).c_str(), "HepMC::Version", 14) == 0 && strncmp(head.at(1).c_str(), "HepMC::Asciiv3", 14) == 0 )
206 {
207 HEPMC3_DEBUG(10, "Attempt ReaderAscii");
208 return std::shared_ptr<Reader>((Reader*) ( new ReaderAscii(stream)));
209 }
210
211 if ( strncmp(head.at(0).c_str(), "HepMC::Version", 14) == 0 && strncmp(head.at(1).c_str(), "HepMC::IO_GenEvent", 18) == 0 )
212 {
213 HEPMC3_DEBUG(10, "Attempt ReaderAsciiHepMC2");
214 return std::shared_ptr<Reader>((Reader*) ( new ReaderAsciiHepMC2(stream)));
215 }
216
217 if ( strncmp(head.at(0).c_str(), "<LesHouchesEvents", 17) == 0)
218 {
219 HEPMC3_DEBUG(10, "Attempt ReaderLHEF");
220 return std::shared_ptr<Reader>((Reader*) ( new ReaderLHEF(stream)));
221 }
222 HEPMC3_DEBUG(10, "Attempt ReaderHEPEVT");
223 std::stringstream st_e(head.at(0).c_str());
224 char attr = ' ';
225 bool HEPEVT = true;
226 int m_i, m_p;
227 while (true)
228 {
229 if (!(st_e >> attr)) {
230 HEPEVT = false;
231 break;
232 }
233 if (attr == ' ') continue;
234 if (attr != 'E') {
235 HEPEVT = false;
236 break;
237 }
238 HEPEVT = static_cast<bool>(st_e >> m_i >> m_p);
239 break;
240 }
241 if (HEPEVT) return std::shared_ptr<Reader>((Reader*) ( new ReaderHEPEVT(stream)));
242 HEPMC3_DEBUG(10, "deduce_reader: all attempts failed");
243 return std::shared_ptr<Reader>(nullptr);
244}
245/** @brief This function will deduce the type of input stream based on its content and will return appropriate Reader*/
246std::shared_ptr<Reader> deduce_reader(std::shared_ptr<std::istream> stream)
247{
248 if (!stream)
249 {
250 HEPMC3_WARNING("Input stream is too short or invalid.");
251 return std::shared_ptr<Reader>(nullptr);
252 }
253 const size_t raw_header_size = 100;
254 std::string raw_header(raw_header_size + 1,'\0');
255 auto fstream = std::dynamic_pointer_cast<std::ifstream>(stream);
256 if (fstream) {
257 fstream->read(&(raw_header[0]), raw_header_size);
258 } else {
259 stream->read(&(raw_header[0]), raw_header_size);
260 }
261 std::vector<std::string> head;
262 head.push_back("");
263 for ( size_t i = 0; i < raw_header_size; ++i) {
264 const char c = raw_header[i];
265 if (c == '\0') break;
266 if (c == '\n') {
267 if (head.back().length() != 0) {
268 head.push_back("");
269 }
270 } else {
271 head.back() += c;
272 }
273 }
274 head.push_back("");
275 if (fstream) {
276 for (size_t i = 0; i < raw_header_size; ++i) { static_cast<std::filebuf*>(fstream->rdbuf())->sungetc(); }
277 HEPMC3_DEBUG(10, "After sungetc() fstream->good()="+std::to_string(fstream->good()));
278 } else {
279 for (size_t i = 0; i < raw_header_size; ++i) { stream->rdbuf()->sungetc(); }
280 HEPMC3_DEBUG(10, "After sungetc() stream->good()="+std::to_string(stream->good()));
281 }
282
283 if (!stream)
284 {
285 HEPMC3_WARNING("Input stream is too short or invalid.");
286 return std::shared_ptr<Reader>(nullptr);
287 }
288
289 if ( strncmp(head.at(0).c_str(),"hmpb",4) == 0 )
290 {
291 std::string libHepMC3protobufIO = "libHepMC3protobufIO.so.3";
292#if defined(__darwin__) || defined(__APPLE__)
293 libHepMC3protobufIO = "libHepMC3protobufIO.dylib";
294#endif
295#if (defined(WIN32) || defined(_WIN32) || defined(__WIN32)) && !defined(__CYGWIN__)
296 libHepMC3protobufIO = "HepMC3protobufIO.dll";
297#endif
298
299 return std::make_shared<ReaderPlugin>(*stream,libHepMC3protobufIO,std::string("newReaderprotobufstream"));
300 }
301
302 if ( strncmp(head.at(0).c_str(), "HepMC::Version", 14) == 0 && strncmp(head.at(1).c_str(), "HepMC::Asciiv3", 14) == 0 )
303 {
304 HEPMC3_DEBUG(10, "Attempt ReaderAscii");
305 return std::shared_ptr<Reader>((Reader*) ( new ReaderAscii(stream)));
306 }
307
308 if ( strncmp(head.at(0).c_str(), "HepMC::Version",14) == 0 && strncmp(head.at(1).c_str(), "HepMC::IO_GenEvent", 18) == 0 )
309 {
310 HEPMC3_DEBUG(10, "Attempt ReaderAsciiHepMC2");
311 return std::shared_ptr<Reader>((Reader*) ( new ReaderAsciiHepMC2(stream)));
312 }
313
314 if ( strncmp(head.at(0).c_str(), "<LesHouchesEvents", 17) == 0)
315 {
316 HEPMC3_DEBUG(10, "Attempt ReaderLHEF");
317 return std::shared_ptr<Reader>((Reader*) ( new ReaderLHEF(stream)));
318 }
319 HEPMC3_DEBUG(10, "Attempt ReaderHEPEVT");
320 std::stringstream st_e(head.at(0).c_str());
321 char attr = ' ';
322 bool HEPEVT = true;
323 int m_i,m_p;
324 while (true)
325 {
326 if (!(st_e >> attr)) {
327 HEPEVT = false;
328 break;
329 }
330 if (attr == ' ') continue;
331 if (attr != 'E') {
332 HEPEVT = false;
333 break;
334 }
335 HEPEVT = static_cast<bool>(st_e >> m_i >> m_p);
336 break;
337 }
338 if (HEPEVT) return std::shared_ptr<Reader>((Reader*) ( new ReaderHEPEVT(stream)));
339 HEPMC3_DEBUG(10, "deduce_reader: all attempts failed");
340 return std::shared_ptr<Reader>(nullptr);
341}
342}
343#endif
#define HEPMC3_WARNING(MESSAGE)
Macro for printing HEPMC3_HEPMC3_WARNING messages.
Definition: Errors.h:27
#define HEPMC3_DEBUG(LEVEL, MESSAGE)
Macro for printing debug messages with appropriate debug level.
Definition: Errors.h:33
#define HEPMC3_ERROR(MESSAGE)
Macro for printing error messages.
Definition: Errors.h:24
Definition of class ReaderAsciiHepMC2.
Definition of class ReaderAscii.
Definition of class ReaderHEPEVT.
Definition of class ReaderLHEF.
Definition of class ReaderPlugin.
Parser for HepMC2 I/O files.
GenEvent I/O parsing for structured text files.
Definition: ReaderAscii.h:29
GenEvent I/O parsing and serialization for HEPEVT files.
Definition: ReaderHEPEVT.h:33
GenEvent I/O parsing and serialization for LHEF files.
Definition: ReaderLHEF.h:35
Base class for all I/O readers.
Definition: Reader.h:25
HepMC3 main namespace.
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...
Fortran common block HEPEVT.