00001 #include <algorithm>
00002 #include <iostream>
00003 #include <sstream>
00004 #include <fstream>
00005 #include <cstring>
00006 #include <string>
00007 #include <vector>
00008
00009 #include <boost/bind.hpp>
00010
00011 #include <xercesc/sax2/Attributes.hpp>
00012 #include <xercesc/dom/DOM.hpp>
00013
00014 #include "FWCore/ParameterSet/interface/ParameterSet.h"
00015 #include "FWCore/Utilities/interface/Exception.h"
00016
00017 #include "GeneratorInterface/LHEInterface/interface/LHEReader.h"
00018 #include "GeneratorInterface/LHEInterface/interface/LHERunInfo.h"
00019 #include "GeneratorInterface/LHEInterface/interface/LHEEvent.h"
00020
00021 #include "Utilities/StorageFactory/interface/IOTypes.h"
00022 #include "Utilities/StorageFactory/interface/Storage.h"
00023 #include "Utilities/StorageFactory/interface/StorageFactory.h"
00024
00025 #include "XMLUtils.h"
00026
00027 XERCES_CPP_NAMESPACE_USE
00028
00029 namespace lhef {
00030
00031 class LHEReader::Source {
00032 public:
00033 Source() {}
00034 virtual ~Source() {}
00035 virtual XMLDocument *createReader(XMLDocument::Handler &handler) = 0;
00036 };
00037
00038 class LHEReader::FileSource : public LHEReader::Source {
00039 public:
00040 FileSource(const std::string &fileURL)
00041 {
00042 Storage *storage =
00043 StorageFactory::get()->open(fileURL,
00044 IOFlags::OpenRead);
00045
00046 if (!storage)
00047 throw cms::Exception("FileOpenError")
00048 << "Could not open LHE file \""
00049 << fileURL << "\" for reading"
00050 << std::endl;
00051
00052 fileStream.reset(new StorageWrap(storage));
00053 }
00054
00055 ~FileSource() {}
00056
00057 XMLDocument *createReader(XMLDocument::Handler &handler)
00058 { return new XMLDocument(fileStream, handler); }
00059
00060 private:
00061 std::auto_ptr<StorageWrap> fileStream;
00062 };
00063
00064 class LHEReader::XMLHandler : public XMLDocument::Handler {
00065 public:
00066 XMLHandler() :
00067 impl(0), gotObject(kNone), mode(kNone),
00068 xmlHeader(0), headerOk(false) {}
00069 ~XMLHandler()
00070 { if (xmlHeader) xmlHeader->release(); }
00071
00072 enum Object {
00073 kNone = 0,
00074 kHeader,
00075 kInit,
00076 kComment,
00077 kEvent
00078 };
00079
00080 protected:
00081 void startElement(const XMLCh *const uri,
00082 const XMLCh *const localname,
00083 const XMLCh *const qname,
00084 const Attributes &attributes);
00085
00086 void endElement(const XMLCh *const uri,
00087 const XMLCh *const localname,
00088 const XMLCh *const qname);
00089
00090 void characters(const XMLCh *const data, const unsigned int length);
00091 void comment(const XMLCh *const data, const unsigned int length);
00092
00093 private:
00094 friend class LHEReader;
00095
00096 DOMImplementation *impl;
00097 std::string buffer;
00098 Object gotObject;
00099 Object mode;
00100 DOMDocument *xmlHeader;
00101 std::vector<DOMElement*> xmlNodes;
00102 bool headerOk;
00103 std::vector<LHERunInfo::Header> headers;
00104 };
00105
00106 static void attributesToDom(DOMElement *dom, const Attributes &attributes)
00107 {
00108 for(unsigned int i = 0; i < attributes.getLength(); i++) {
00109 const XMLCh *name = attributes.getQName(i);
00110 const XMLCh *value = attributes.getValue(i);
00111
00112 dom->setAttribute(name, value);
00113 }
00114 }
00115
00116 static void fillHeader(LHERunInfo::Header &header, const char *data,
00117 int len = -1)
00118 {
00119 const char *end = len >= 0 ? (data + len) : 0;
00120 while(*data && (!end || data < end)) {
00121 std::size_t len = std::strcspn(data, "\r\n");
00122 if (end && data + len > end)
00123 len = end - data;
00124 if (data[len] == '\r' && data[len + 1] == '\n')
00125 len += 2;
00126 else if (data[len])
00127 len++;
00128 header.addLine(std::string(data, len));
00129 data += len;
00130 }
00131 }
00132
00133 void LHEReader::XMLHandler::startElement(const XMLCh *const uri,
00134 const XMLCh *const localname,
00135 const XMLCh *const qname,
00136 const Attributes &attributes)
00137 {
00138 std::string name((const char*)XMLSimpleStr(qname));
00139
00140 if (!headerOk) {
00141 if (name != "LesHouchesEvents")
00142 throw cms::Exception("InvalidFormat")
00143 << "LHE file has invalid header" << std::endl;
00144 headerOk = true;
00145 return;
00146 }
00147
00148 if (mode == kHeader) {
00149 DOMElement *elem = xmlHeader->createElement(qname);
00150 attributesToDom(elem, attributes);
00151 xmlNodes.back()->appendChild(elem);
00152 xmlNodes.push_back(elem);
00153 return;
00154 } else if (mode != kNone)
00155 throw cms::Exception("InvalidFormat")
00156 << "LHE file has invalid format" << std::endl;
00157
00158 if (name == "header") {
00159 if (!impl)
00160 impl = DOMImplementationRegistry::getDOMImplementation(
00161 XMLUniStr("Core"));
00162 xmlHeader = impl->createDocument(0, qname, 0);
00163 xmlNodes.resize(1);
00164 xmlNodes[0] = xmlHeader->getDocumentElement();
00165 mode = kHeader;
00166 } if (name == "init")
00167 mode = kInit;
00168 else if (name == "event")
00169 mode = kEvent;
00170
00171 if (mode == kNone)
00172 throw cms::Exception("InvalidFormat")
00173 << "LHE file has invalid format" << std::endl;
00174
00175 buffer.clear();
00176 }
00177
00178 void LHEReader::XMLHandler::endElement(const XMLCh *const uri,
00179 const XMLCh *const localname,
00180 const XMLCh *const qname)
00181 {
00182 if (mode) {
00183 if (mode == kHeader && xmlNodes.size() > 1) {
00184 xmlNodes.resize(xmlNodes.size() - 1);
00185 return;
00186 } else if (mode == kHeader) {
00187 std::auto_ptr<DOMWriter> writer(
00188 static_cast<DOMImplementationLS*>(
00189 impl)->createDOMWriter());
00190 writer->setEncoding(XMLUniStr("UTF-8"));
00191 XMLSimpleStr buffer(
00192 writer->writeToString(*xmlNodes[0]));
00193 LHERunInfo::Header header("header");
00194 const char *p =
00195 std::strchr((const char*)buffer, '>') + 1;
00196 const char *q = std::strrchr(p, '<');
00197 fillHeader(header, p, q - p);
00198 headers.push_back(header);
00199
00200 xmlHeader->release();
00201 xmlHeader = 0;
00202 }
00203
00204 if (gotObject != kNone)
00205 throw cms::Exception("InvalidState")
00206 << "Unexpected pileup in"
00207 " LHEReader::XMLHandler::endElement"
00208 << std::endl;
00209
00210 gotObject = mode;
00211 mode = kNone;
00212 }
00213 }
00214
00215 void LHEReader::XMLHandler::characters(const XMLCh *const data_,
00216 const unsigned int length)
00217 {
00218 if (mode == kHeader) {
00219 DOMText *text = xmlHeader->createTextNode(data_);
00220 xmlNodes.back()->appendChild(text);
00221 return;
00222 }
00223
00224 if (XMLSimpleStr::isAllSpaces(data_, length))
00225 return;
00226
00227 unsigned int offset = 0;
00228 while(offset < length && XMLSimpleStr::isSpace(data_[offset]))
00229 offset++;
00230
00231 XMLSimpleStr data(data_ + offset);
00232
00233 if (mode == kNone)
00234 throw cms::Exception("InvalidFormat")
00235 << "LHE file has invalid format" << std::endl;
00236
00237 buffer.append(data);
00238 }
00239
00240 void LHEReader::XMLHandler::comment(const XMLCh *const data_,
00241 const unsigned int length)
00242 {
00243 if (mode == kHeader) {
00244 DOMComment *comment = xmlHeader->createComment(data_);
00245 xmlNodes.back()->appendChild(comment);
00246 return;
00247 }
00248
00249 XMLSimpleStr data(data_);
00250
00251 LHERunInfo::Header header;
00252 fillHeader(header, data);
00253 headers.push_back(header);
00254 }
00255
00256 LHEReader::LHEReader(const edm::ParameterSet ¶ms) :
00257 fileURLs(params.getUntrackedParameter< std::vector<std::string> >("fileNames")),
00258 firstEvent(params.getUntrackedParameter<unsigned int>("seekEvent", 0)),
00259 maxEvents(params.getUntrackedParameter<int>("limitEvents", -1)),
00260 curIndex(0), handler(new XMLHandler())
00261 {
00262 }
00263
00264 LHEReader::LHEReader(const std::vector<std::string> &fileNames,
00265 unsigned int firstEvent) :
00266 fileURLs(fileNames), firstEvent(firstEvent), maxEvents(-1),
00267 curIndex(0), handler(new XMLHandler())
00268 {
00269 }
00270
00271 LHEReader::~LHEReader()
00272 {
00273 }
00274
00275 boost::shared_ptr<LHEEvent> LHEReader::next()
00276 {
00277 while(curDoc.get() || curIndex < fileURLs.size()) {
00278 if (!curDoc.get()) {
00279 curSource.reset(new FileSource(fileURLs[curIndex++]));
00280 curDoc.reset(curSource->createReader(*handler));
00281 curRunInfo.reset();
00282 }
00283
00284 XMLHandler::Object event = handler->gotObject;
00285 handler->gotObject = XMLHandler::kNone;
00286
00287 std::istringstream data;
00288 if (event != XMLHandler::kNone) {
00289 data.str(handler->buffer);
00290 handler->buffer.clear();
00291 }
00292
00293 switch(event) {
00294 case XMLHandler::kNone:
00295 if (!curDoc->parse())
00296 curDoc.reset();
00297 break;
00298
00299 case XMLHandler::kHeader:
00300 break;
00301
00302 case XMLHandler::kInit:
00303 curRunInfo.reset(new LHERunInfo(data));
00304 std::for_each(handler->headers.begin(),
00305 handler->headers.end(),
00306 boost::bind(&LHERunInfo::addHeader,
00307 curRunInfo.get(), _1));
00308 handler->headers.clear();
00309 break;
00310
00311 case XMLHandler::kComment:
00312 break;
00313
00314 case XMLHandler::kEvent:
00315 if (!curRunInfo.get())
00316 throw cms::Exception("InvalidState")
00317 << "Got LHE event without"
00318 " initialization." << std::endl;
00319
00320 if (firstEvent > 0) {
00321 firstEvent--;
00322 continue;
00323 }
00324
00325 if (maxEvents == 0)
00326 return boost::shared_ptr<LHEEvent>();
00327 else if (maxEvents > 0)
00328 maxEvents--;
00329
00330 return boost::shared_ptr<LHEEvent>(
00331 new LHEEvent(curRunInfo, data));
00332 }
00333 }
00334
00335 return boost::shared_ptr<LHEEvent>();
00336 }
00337
00338 }