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