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 void reset() { headerOk = false; }
00081
00082 protected:
00083 void startElement(const XMLCh *const uri,
00084 const XMLCh *const localname,
00085 const XMLCh *const qname,
00086 const Attributes &attributes);
00087
00088 void endElement(const XMLCh *const uri,
00089 const XMLCh *const localname,
00090 const XMLCh *const qname);
00091
00092 void characters(const XMLCh *const data, const unsigned int length);
00093 void comment(const XMLCh *const data, const unsigned int length);
00094
00095 private:
00096 friend class LHEReader;
00097
00098 DOMImplementation *impl;
00099 std::string buffer;
00100 Object gotObject;
00101 Object mode;
00102 DOMDocument *xmlHeader;
00103 std::vector<DOMElement*> xmlNodes;
00104 bool headerOk;
00105 std::vector<LHERunInfo::Header> headers;
00106 };
00107
00108 static void attributesToDom(DOMElement *dom, const Attributes &attributes)
00109 {
00110 for(unsigned int i = 0; i < attributes.getLength(); i++) {
00111 const XMLCh *name = attributes.getQName(i);
00112 const XMLCh *value = attributes.getValue(i);
00113
00114 dom->setAttribute(name, value);
00115 }
00116 }
00117
00118 static void fillHeader(LHERunInfo::Header &header, const char *data,
00119 int len = -1)
00120 {
00121 const char *end = len >= 0 ? (data + len) : 0;
00122 while(*data && (!end || data < end)) {
00123 std::size_t len = std::strcspn(data, "\r\n");
00124 if (end && data + len > end)
00125 len = end - data;
00126 if (data[len] == '\r' && data[len + 1] == '\n')
00127 len += 2;
00128 else if (data[len])
00129 len++;
00130 header.addLine(std::string(data, len));
00131 data += len;
00132 }
00133 }
00134
00135 void LHEReader::XMLHandler::startElement(const XMLCh *const uri,
00136 const XMLCh *const localname,
00137 const XMLCh *const qname,
00138 const Attributes &attributes)
00139 {
00140 std::string name((const char*)XMLSimpleStr(qname));
00141
00142 if (!headerOk) {
00143 if (name != "LesHouchesEvents")
00144 throw cms::Exception("InvalidFormat")
00145 << "LHE file has invalid header" << std::endl;
00146 headerOk = true;
00147 return;
00148 }
00149
00150 if (mode == kHeader) {
00151 DOMElement *elem = xmlHeader->createElement(qname);
00152 attributesToDom(elem, attributes);
00153 xmlNodes.back()->appendChild(elem);
00154 xmlNodes.push_back(elem);
00155 return;
00156 } else if (mode != kNone)
00157 throw cms::Exception("InvalidFormat")
00158 << "LHE file has invalid format" << std::endl;
00159
00160 if (name == "header") {
00161 if (!impl)
00162 impl = DOMImplementationRegistry::getDOMImplementation(
00163 XMLUniStr("Core"));
00164 xmlHeader = impl->createDocument(0, qname, 0);
00165 xmlNodes.resize(1);
00166 xmlNodes[0] = xmlHeader->getDocumentElement();
00167 mode = kHeader;
00168 } if (name == "init")
00169 mode = kInit;
00170 else if (name == "event")
00171 mode = kEvent;
00172
00173 if (mode == kNone)
00174 throw cms::Exception("InvalidFormat")
00175 << "LHE file has invalid format" << std::endl;
00176
00177 buffer.clear();
00178 }
00179
00180 void LHEReader::XMLHandler::endElement(const XMLCh *const uri,
00181 const XMLCh *const localname,
00182 const XMLCh *const qname)
00183 {
00184 if (mode) {
00185 if (mode == kHeader && xmlNodes.size() > 1) {
00186 xmlNodes.resize(xmlNodes.size() - 1);
00187 return;
00188 } else if (mode == kHeader) {
00189 std::auto_ptr<DOMWriter> writer(
00190 static_cast<DOMImplementationLS*>(
00191 impl)->createDOMWriter());
00192 writer->setEncoding(XMLUniStr("UTF-8"));
00193
00194 for(DOMNode *node = xmlNodes[0]->getFirstChild();
00195 node; node = node->getNextSibling()) {
00196 XMLSimpleStr buffer(
00197 writer->writeToString(*node));
00198
00199 std::string type;
00200 const char *p, *q;
00201 DOMElement *elem;
00202
00203 switch(node->getNodeType()) {
00204 case DOMNode::ELEMENT_NODE:
00205 elem = static_cast<DOMElement*>(node);
00206 type = (const char*)XMLSimpleStr(
00207 elem->getTagName());
00208 p = std::strchr((const char*)buffer,
00209 '>') + 1;
00210 q = std::strrchr(p, '<');
00211 break;
00212 case DOMNode::COMMENT_NODE:
00213 type = "";
00214 p = buffer + 4;
00215 q = buffer + strlen(buffer) - 3;
00216 break;
00217 default:
00218 type = "<>";
00219 p = buffer +
00220 std::strspn(buffer, " \t\r\n");
00221 if (!*p)
00222 continue;
00223 q = p + strlen(p);
00224 }
00225
00226 LHERunInfo::Header header(type);
00227 fillHeader(header, p, q - p);
00228 headers.push_back(header);
00229 }
00230
00231 xmlHeader->release();
00232 xmlHeader = 0;
00233 }
00234
00235 if (gotObject != kNone)
00236 throw cms::Exception("InvalidState")
00237 << "Unexpected pileup in"
00238 " LHEReader::XMLHandler::endElement"
00239 << std::endl;
00240
00241 gotObject = mode;
00242 mode = kNone;
00243 }
00244 }
00245
00246 void LHEReader::XMLHandler::characters(const XMLCh *const data_,
00247 const unsigned int length)
00248 {
00249 if (mode == kHeader) {
00250 DOMText *text = xmlHeader->createTextNode(data_);
00251 xmlNodes.back()->appendChild(text);
00252 return;
00253 }
00254
00255 if (XMLSimpleStr::isAllSpaces(data_, length))
00256 return;
00257
00258 unsigned int offset = 0;
00259 while(offset < length && XMLSimpleStr::isSpace(data_[offset]))
00260 offset++;
00261
00262 XMLSimpleStr data(data_ + offset);
00263
00264 if (mode == kNone)
00265 throw cms::Exception("InvalidFormat")
00266 << "LHE file has invalid format" << std::endl;
00267
00268 buffer.append(data);
00269 }
00270
00271 void LHEReader::XMLHandler::comment(const XMLCh *const data_,
00272 const unsigned int length)
00273 {
00274 if (mode == kHeader) {
00275 DOMComment *comment = xmlHeader->createComment(data_);
00276 xmlNodes.back()->appendChild(comment);
00277 return;
00278 }
00279
00280 XMLSimpleStr data(data_);
00281
00282 LHERunInfo::Header header;
00283 fillHeader(header, data);
00284 headers.push_back(header);
00285 }
00286
00287 LHEReader::LHEReader(const edm::ParameterSet ¶ms) :
00288 fileURLs(params.getUntrackedParameter< std::vector<std::string> >("fileNames")),
00289 firstEvent(params.getUntrackedParameter<unsigned int>("skipEvents", 0)),
00290 maxEvents(params.getUntrackedParameter<int>("limitEvents", -1)),
00291 curIndex(0), handler(new XMLHandler())
00292 {
00293 }
00294
00295 LHEReader::LHEReader(const std::vector<std::string> &fileNames,
00296 unsigned int firstEvent) :
00297 fileURLs(fileNames), firstEvent(firstEvent), maxEvents(-1),
00298 curIndex(0), handler(new XMLHandler())
00299 {
00300 }
00301
00302 LHEReader::~LHEReader()
00303 {
00304 }
00305
00306 boost::shared_ptr<LHEEvent> LHEReader::next()
00307 {
00308 while(curDoc.get() || curIndex < fileURLs.size()) {
00309 if (!curDoc.get()) {
00310 curSource.reset(new FileSource(fileURLs[curIndex++]));
00311 handler->reset();
00312 curDoc.reset(curSource->createReader(*handler));
00313 curRunInfo.reset();
00314 }
00315
00316 XMLHandler::Object event = handler->gotObject;
00317 handler->gotObject = XMLHandler::kNone;
00318
00319 std::istringstream data;
00320 if (event != XMLHandler::kNone) {
00321 data.str(handler->buffer);
00322 handler->buffer.clear();
00323 }
00324
00325 switch(event) {
00326 case XMLHandler::kNone:
00327 if (!curDoc->parse())
00328 curDoc.reset();
00329 break;
00330
00331 case XMLHandler::kHeader:
00332 break;
00333
00334 case XMLHandler::kInit:
00335 curRunInfo.reset(new LHERunInfo(data));
00336
00337 std::for_each(handler->headers.begin(),
00338 handler->headers.end(),
00339 boost::bind(&LHERunInfo::addHeader,
00340 curRunInfo.get(), _1));
00341 handler->headers.clear();
00342 break;
00343
00344 case XMLHandler::kComment:
00345 break;
00346
00347 case XMLHandler::kEvent:
00348 if (!curRunInfo.get())
00349 throw cms::Exception("InvalidState")
00350 << "Got LHE event without"
00351 " initialization." << std::endl;
00352
00353 if (firstEvent > 0) {
00354 firstEvent--;
00355 continue;
00356 }
00357
00358 if (maxEvents == 0)
00359 return boost::shared_ptr<LHEEvent>();
00360 else if (maxEvents > 0)
00361 maxEvents--;
00362
00363 return boost::shared_ptr<LHEEvent>(
00364 new LHEEvent(curRunInfo, data));
00365 }
00366 }
00367
00368 return boost::shared_ptr<LHEEvent>();
00369 }
00370
00371 }