/* * hddm-cpp : tool that reads in a HDDM document (Hall D Data Model) * and writes a c++ class library that expresses the model * in c++ classes. It also generates input/output methods * for serializing/deserializing these classes in a form * suitable for passing over a network or storing on disk. * * Original version - Richard Jones, January 25, 2006. * * * Programmer's Notes: * ------------------- * 1. The HDDM specification describes data files using xml. For * information about the contents and structure of HDDM documents * see the web page that describes the data model. * * 2. Access by hddm-cpp to the xml source is through the industry- * standard Document Object Model (DOM) interface. * * 3. The code has been tested with the xerces-c DOM implementation from * Apache, and is intended to be used with the xerces-c library. * * 4. Output is sent to .hpp and .cpp where * is by default "hddm_x" and can be changed with the -o option. * * 5. As a by-product of using the DOM parser to access the xml source, * hddm-cpp verifies the source for well-formedness. Therefore it may * also be used to check the xml data model document. * * * Implementation Notes: * --------------------- * 1. The binary stream consists of the hddm data model in the form * of a well-formed xml header, followed by binary data. * * 2. The binary data consist of a sequence of event records, which are * repetitions of the basic data model in a serial representation. * * 3. Each element is output to the stream in the order it appears in * the data model, prefixed by an exclusive byte count. * * 4. Any c++ application compiled with the hddm header file that is * generated by hddm-cpp is able to read any hddm binary file that * was written using the same hddm class, ie. the * document tags must be a non-colliding set (see matching rules). * * 5. The input/output features of the class library produced by hddm-cpp * are implemented on top of the "xstream" binary i/o class by Claudio * Valente which provides serialization/deserialization of binary data * using network byte-ordering (RFC-1832), compression/decompression, * and error checking capability used to make the hddm i/o facility * flexible and robust. */ #include "XString.hpp" #include "XParsers.hpp" //#include //#include //#include //#include #include #include #include #include #define X(str) XString(str).unicode_str() #define S(str) str.c_str() using namespace xercesc; XString classPrefix; void usage() { std::cerr << "\nUsage:\n" << " hddm-cpp [-v | -o ] {HDDM file}\n\n" << "Options:\n" << " -v validate only\n" << " -o write to .h" << std::endl; } class XtString : public XString { /* XString class with a few extra methods for creating type * strings that are useful in creating class names */ public: XtString() {}; XtString(const char* s): XString(s) {}; XtString(const XMLCh* p): XString(p) {}; XtString(const std::string& s): XString(s) {}; XtString(const XString& x): XString(x) {}; XtString(const XtString& t): XString((XString&)t) {}; ~XtString(); XtString& plural(); XtString& simpleType(); XtString& listType(); private: std::list fStringCollection; }; class CodeBuilder { /* The methods in this class are used to write the c++ code * that implements the hddm class library. */ public: std::ofstream hFile; std::ofstream cFile; CodeBuilder() {}; ~CodeBuilder() {}; void checkConsistency(DOMElement* el, DOMElement* elref); void writeHeader(DOMElement* el); void constructDocument(DOMElement* el); void constructGroup(DOMElement* el); void constructMethods(DOMElement* el); void constructIOstreams(DOMElement* el); void constructUnpackers(DOMElement* el); void constructPackers(DOMElement* el); void writeMatcher(); private: std::vector tagList; typedef std::map parentList_t; typedef std::map parentTable_t; parentTable_t parents; }; int main(int argC, char* argV[]) { try { XMLPlatformUtils::Initialize(); } catch (const XMLException* toCatch) { XtString msg(toCatch->getMessage()); std::cerr << "hddm-cpp: Error during initialization! :\n" << msg << std::endl; return 1; } if (argC < 2) { usage(); return 1; } else if ((argC == 2) && (strcmp(argV[1], "-?") == 0)) { usage(); return 2; } XtString xmlFile; XtString hFilename; bool verifyOnly = false; int argInd; for (argInd = 1; argInd < argC; argInd++) { if (argV[argInd][0] != '-') { break; } if (strcmp(argV[argInd],"-v") == 0) { verifyOnly = true; } else if (strcmp(argV[argInd],"-o") == 0) { hFilename = XtString(argV[++argInd]); } else { std::cerr << "Unknown option \'" << argV[argInd] << "\', ignoring it\n" << std::endl; } } if (argInd != argC - 1) { usage(); return 1; } xmlFile = XtString(argV[argInd]); #if defined OLD_STYLE_XERCES_PARSER DOMDocument* document = parseInputDocument(xmlFile.c_str(),false); #else DOMDocument* document = buildDOMDocument(xmlFile.c_str(),false); #endif if (document == 0) { std::cerr << "hddm-cpp : Error parsing HDDM document, " << "cannot continue" << std::endl; return 1; } DOMElement* rootEl = document->getDocumentElement(); XtString rootS(rootEl->getTagName()); if (rootS != "HDDM") { std::cerr << "hddm-cpp error: root element of input document is " << "\"" << rootS << "\", expected \"HDDM\"" << std::endl; return 1; } XtString classS(rootEl->getAttribute(X("class"))); classPrefix = classS; XtString hname; if (verifyOnly) { hname = "/dev/null"; } else if (hFilename.size()) { hname = hFilename + ".hpp"; } else { hname = "hddm_" + classPrefix + ".hpp"; } CodeBuilder builder; builder.hFile.open(hname.c_str()); if (! builder.hFile.is_open()) { std::cerr << "hddm-cpp error: unable to open output file " << hname << std::endl; return 1; } XtString cname; if (verifyOnly) { cname = "/dev/null"; } else if (hFilename.size()) { cname = hFilename + ".cpp"; } else { cname = "hddm_" + classPrefix + ".cpp"; } builder.cFile.open(cname.c_str()); if (! builder.cFile.is_open()) { std::cerr << "hddm-cpp error: unable to open output file " << cname << std::endl; return 1; } builder.hFile << "/*" << std::endl << " * " << hname << " - DO NOT EDIT THIS FILE" << std::endl << " *" << std::endl << " * This file was generated automatically by hddm-cpp" << " from the file" << std::endl << " * " << xmlFile << std::endl << std::endl << " * This header file defines the c++ classes that" << " hold the data" << std::endl << " * described in the data model" << " (from " << xmlFile << "). " << std::endl << " *" << std::endl << " * The hddm data model tool set was written by" << std::endl << " * Richard Jones, University of Connecticut." << std::endl << " *" << std::endl << " * For more information see the following web site"<< std::endl << " *" << std::endl << " * http://zeus.phys.uconn.edu/halld/datamodel/doc" << std::endl << " *" << std::endl << " */" << std::endl << std::endl; builder.cFile << "/*" << std::endl << " * " << cname << " - DO NOT EDIT THIS FILE" << std::endl << " *" << std::endl << " * This file was generated automatically by hddm-cpp" << " from the file" << std::endl << " * " << xmlFile << std::endl << std::endl << " * This c++ source implements the methods for" << " the classes " << std::endl << " * described in the data model" << " (from " << xmlFile << "). " << std::endl << " *" << std::endl << " * The hddm data model tool set was written by" << std::endl << " * Richard Jones, University of Connecticut." << std::endl << " *" << std::endl << " * For more information see the following web site"<< std::endl << " *" << std::endl << " * http://zeus.phys.uconn.edu/halld/datamodel/doc" << std::endl << " */" << std::endl << std::endl; builder.hFile << "#ifndef SAW_s_HDDM" << std::endl << "#define SAW_s_HDDM" << std::endl << std::endl << "#include " << std::endl << "#include " << std::endl << "#include " << std::endl << "#include " << std::endl << std::endl << "namespace hddm_s {" << std::endl << std::endl; builder.cFile << "#include " << std::endl << "#include \"" << hname << "\"" << std::endl << std::endl << "using namespace hddm_s;" << std::endl; builder.constructGroup(rootEl); builder.constructMethods(rootEl); builder.constructIOstreams(rootEl); builder.constructUnpackers(rootEl); builder.constructPackers(rootEl); builder.hFile << std::endl << "}" << std::endl << "#endif /* SAW_s_HDDM */" << std::endl; XMLPlatformUtils::Terminate(); return 0; } XtString::~XtString() { std::list::iterator iter; for (iter = fStringCollection.begin(); iter != fStringCollection.end(); ++iter) { delete *iter; } } XtString& XtString::plural() { XtString* p = new XtString(*this); fStringCollection.push_back(p); XtString::size_type len = p->size(); if (len > 3 && p->substr(len-3,3) == "tum") { p->replace(len-3,3,"ta"); } else if (len > 1 && p->substr(len-3,3) == "ies") { p->replace(len-3,3,"iesList"); } else if (len > 2 && p->substr(len-2,2) == "ex") { p->replace(len-2,2,"ices"); } else if (len > 2 && p->substr(len-2,2) == "sh") { p->replace(len-2,2,"shes"); } else if (len > 1 && p->substr(len-1,1) == "s") { p->replace(len-1,1,"ses"); } else if (len > 1) { *p += "s"; } return *p; } /* Map from tag name to name of the corresponding c-structure * for the case of simple tags (those that do not repeat) */ XtString& XtString::simpleType() { XtString* p = new XtString(*this); fStringCollection.push_back(p); (*p)[0] = toupper((*p)[0]); *p = *p + "_t"; return *p; } /* Map from tag name to name of the corresponding c-structure * for the case of list tags (those that may repeat) */ XtString& XtString::listType() { XtString& r = plural(); r[0] = toupper(r[0]); r = r + "_t"; return r; } /* Verify that the tag group under this element does not collide * with existing tag group elref, otherwise exit with fatal error */ void CodeBuilder::checkConsistency(DOMElement* el, DOMElement* elref) { XtString tagS(el->getTagName()); if (el->getParentNode() == elref->getParentNode()) { std::cerr << "hddm-cpp error: tag " << "\"" << tagS << "\" is duplicated within one context in xml document." << std::endl; exit(1); } DOMNamedNodeMap* oldAttr = elref->getAttributes(); DOMNamedNodeMap* newAttr = el->getAttributes(); int listLength = oldAttr->getLength(); for (int n = 0; n < listLength; n++) { XtString nameS(oldAttr->item(n)->getNodeName()); XtString oldS(elref->getAttribute(X(nameS))); XtString newS(el->getAttribute(X(nameS))); if (nameS == "minOccurs") { continue; } else if (nameS == "maxOccurs") { int maxold = (oldS == "unbounded")? 9999 : atoi(S(oldS)); int maxnew = (newS == "unbounded")? 9999 : atoi(S(newS)); if (maxold*maxnew <= maxold) { std::cerr << "hddm-cpp error: inconsistent maxOccurs usage by tag " << "\"" << tagS << "\" in xml document." << std::endl; exit(1); } } else if (newS != oldS) { std::cerr << "hddm-cpp error: inconsistent usage of attribute " << "\"" << nameS << "\" in tag " << "\"" << tagS << "\" in xml document." << std::endl; exit(1); } } listLength = newAttr->getLength(); for (int n = 0; n < listLength; n++) { XtString nameS(newAttr->item(n)->getNodeName()); XtString oldS(elref->getAttribute(X(nameS))); XtString newS(el->getAttribute(X(nameS))); if (nameS == "minOccurs") { continue; } else if (nameS == "maxOccurs") { int maxold = (oldS == "unbounded")? 9999 : atoi(S(oldS)); int maxnew = (newS == "unbounded")? 9999 : atoi(S(newS)); if (maxold*maxnew <= maxnew) { std::cerr << "hddm-cpp error: inconsistent maxOccurs usage by tag " << "\"" << tagS << "\" in xml document." << std::endl; exit(1); } } else if (newS != oldS) { std::cerr << "hddm-cpp error: inconsistent usage of attribute " << "\"" << nameS << "\" in tag " << "\"" << tagS << "\" in xml document." << std::endl; exit(1); } } DOMNodeList* oldList = elref->getChildNodes(); DOMNodeList* newList = el->getChildNodes(); listLength = oldList->getLength(); if (newList->getLength() != listLength) { std::cerr << "hddm-cpp error: inconsistent usage of tag " << "\"" << tagS << "\" in xml document." << std::endl; exit(1); } for (int n = 0; n < listLength; n++) { DOMNode* cont = oldList->item(n); XtString nameS(cont->getNodeName()); short type = cont->getNodeType(); if (type == DOMNode::ELEMENT_NODE) { DOMNodeList* contList = el->getElementsByTagName(X(nameS)); if (contList->getLength() != 1) { std::cerr << "hddm-cpp error: inconsistent usage of tag " << "\"" << tagS << "\" in xml document." << std::endl; exit(1); } } } } /* Write declaration of the classes for this tag to the header file */ void CodeBuilder::writeHeader(DOMElement* el) { XtString tagS(el->getTagName()); parentList_t parentNames; DOMElement* topEl = el->getOwnerDocument()->getDocumentElement(); DOMNodeList* allEl = topEl->getElementsByTagName(X(tagS)); for (int ic = 0; ic < allEl->getLength(); ic++) { DOMNode* hostEl = allEl->item(ic)->getParentNode(); XtString hostS(hostEl->getNodeName()); parentNames[hostS] = hostEl; } parents[el] = parentNames; hFile << std::endl << "class " << tagS.listType() << ": public std::vector<" << tagS.simpleType() << ">" << std::endl << "{" << std::endl << " public:" << std::endl; parentList_t::iterator iter; for (iter = parentNames.begin(); iter != parentNames.end(); ++iter) { XtString hostS(iter->first); if (hostS == "HDDM") { hFile << " " << tagS.listType() << "();" << std::endl; parentNames.erase(iter); } else { hFile << " " << tagS.listType() << "(const " << hostS.listType() << "* " << "host, int index);" << std::endl; } } hFile << " friend class iterator;" << std::endl << " class iterator: public std::vector<" << tagS.simpleType() << ">::iterator" << std::endl << " {" << std::endl << " public:" << std::endl << " friend class " << tagS.listType() << ";" << std::endl << " friend class const_iterator;" << std::endl << " iterator() {};" << std::endl << " iterator(const iterator& src);" << std::endl << " iterator& operator=" << "(const iterator& src);" << std::endl << " iterator& operator++();" << std::endl << " iterator operator++(int);" << std::endl << " iterator& operator--();" << std::endl << " iterator operator--(int);" << std::endl << " //private: /* gcc compiler bug */" << std::endl << " " << tagS.listType() << "* list;" << std::endl; for (iter = parentNames.begin(); iter != parentNames.end(); ++iter) { XtString hostS(iter->first); hFile << " " << hostS.listType() << "::iterator " << hostS << ";" << std::endl; } hFile << " };" << std::endl << " friend class const_iterator;" << std::endl << " class const_iterator: public std::vector<" << tagS.simpleType() << ">::const_iterator" << std::endl << " {" << std::endl << " public:" << std::endl << " friend class " << tagS.listType() << ";" << std::endl << " const_iterator() {};" << std::endl << " const_iterator(const iterator& src);" << std::endl << " const_iterator(const const_iterator& src);" << std::endl << " const_iterator& operator=" << "(const iterator& src);" << std::endl << " const_iterator& operator=" << "(const const_iterator& src);" << std::endl << " const_iterator& operator++();" << std::endl << " const_iterator operator++(int);" << std::endl << " const_iterator& operator--();" << std::endl << " const_iterator operator--(int);" << std::endl << " //private: /* gcc compiler bug */" << std::endl << " const " << tagS.listType() << "* list;" << std::endl; for (iter = parentNames.begin(); iter != parentNames.end(); ++iter) { XtString hostS(iter->first); hFile << " " << hostS.listType() << "::const_iterator " << hostS << ";" << std::endl; } hFile << " };" << std::endl << " " << tagS.simpleType() << "& create();" << std::endl << " private:" << std::endl; for (iter = parentNames.begin(); iter != parentNames.end(); ++iter) { XtString hostS(iter->first); hFile << " const " << hostS.listType() << "* host_" << hostS.plural() << ";" << std::endl << " const int host_" << hostS << ";" << std::endl; } hFile << "};" << std::endl; hFile << std::endl << "class " << tagS.simpleType() << std::endl << "{" << std::endl << " public:" << std::endl << " friend class " << tagS.listType() << ";" << std::endl; DOMNodeList* contList = el->getChildNodes(); if (contList->getLength() > 0) { hFile << " ~" << tagS.simpleType() << "();" << std::endl; } DOMNamedNodeMap* varList = el->getAttributes(); int varCount = varList->getLength(); for (int v = 0; v < varCount; v++) { DOMNode* var = varList->item(v); XtString typeS(var->getNodeValue()); XtString nameS(var->getNodeName()); if (typeS == "int") { hFile << " int32_t " << nameS << ";" << std::endl; } else if (typeS == "long") { hFile << " int64_t " << nameS << ";" << std::endl; } else if (typeS == "float") { hFile << " float " << nameS << ";" << std::endl; } else if (typeS == "double") { hFile << " double " << nameS << ";" << std::endl; } else if (typeS == "boolean") { hFile << " int " << nameS << ";" << std::endl; } else if (typeS == "string") { hFile << " std::string " << nameS << ";" << std::endl; } else if (typeS == "anyURI") { hFile << " std::string " << nameS << ";" << std::endl; } else if (typeS == "Particle_t") { hFile << " Particle_t " << nameS << ";" << std::endl; } else { /* ignore attributes with unrecognized values */ } } int contLength = contList->getLength(); for (int c = 0; c < contLength; c++) { DOMNode* cont = contList->item(c); XtString nameS(cont->getNodeName()); short type = cont->getNodeType(); if (type == DOMNode::ELEMENT_NODE) { DOMElement* contEl = (DOMElement*) cont; hFile << " " << nameS.listType() << "* " << nameS.plural() << ";" << std::endl; XtString repS(contEl->getAttribute(X("maxOccurs"))); int rep = (repS == "unbounded")? 9999 : atoi(S(repS)); hFile << " " << nameS.simpleType() << "* " << nameS << ((rep > 1)? "(int n)" : "()") << ";" << std::endl; } } hFile << " private:" << std::endl << " " << tagS.simpleType() << "(const " << tagS.listType() << "* host, int index);" << std::endl; hFile << "};" << std::endl; } /* Generate class declarations for this tag and its descendants; * this function calls itself recursively */ void CodeBuilder::constructGroup(DOMElement* el) { XtString tagS(el->getTagName()); std::vector::iterator iter; for (iter = tagList.begin(); iter != tagList.end(); iter++) { DOMElement* targEl = *iter; XtString targS(targEl->getTagName()); if (tagS == targS) { checkConsistency(el,targEl); tagList.erase(iter); tagList.push_back(targEl); return; } } if (tagS != "HDDM") { tagList.push_back(el); hFile << "class " << tagS.simpleType() << ";" << std::endl << "class " << tagS.listType() << ";" << std::endl; } DOMNodeList* contList = el->getChildNodes(); int contLength = contList->getLength(); for (int c = 0; c < contLength; c++) { DOMNode* cont = contList->item(c); short type = cont->getNodeType(); if (type == DOMNode::ELEMENT_NODE) { DOMElement* contEl = (DOMElement*) cont; constructGroup(contEl); } } if (tagS == "HDDM") { std::vector::iterator iter; for (iter = tagList.begin(); iter != tagList.end(); iter++) { writeHeader(*iter); } XtString tagS("Record"); hFile << std::endl << "class " << tagS.simpleType() << std::endl << "{" << std::endl << " public:" << std::endl << " " << tagS.simpleType() << "();" << std::endl << " ~" << tagS.simpleType() << "();" << std::endl; DOMNodeList* contList = el->getChildNodes(); int contLength = contList->getLength(); for (int c = 0; c < contLength; c++) { DOMNode* cont = contList->item(c); XtString nameS(cont->getNodeName()); short type = cont->getNodeType(); if (type == DOMNode::ELEMENT_NODE) { DOMElement* contEl = (DOMElement*) cont; hFile << " " << nameS.listType() << "* " << nameS.plural() << ";" << std::endl; XtString repS(contEl->getAttribute(X("maxOccurs"))); int rep = (repS == "unbounded")? 9999 : atoi(S(repS)); hFile << " " << nameS.simpleType() << "* " << nameS << ((rep > 1)? "(int n)" : "()") << ";" << std::endl; } } hFile << std::endl; for (iter = tagList.begin(); iter != tagList.end(); iter++) { XtString tagS((*iter)->getTagName()); hFile << " " << tagS.listType() << "::iterator&" << " begin(" << tagS.listType() << "::iterator& p);" << std::endl << " " << tagS.listType() << "::iterator&" << " end(" << tagS.listType() << "::iterator& p);" << std::endl << " " << tagS.listType() << "::const_iterator&" << " begin(" << tagS.listType() << "::const_iterator& p) const;" << std::endl << " " << tagS.listType() << "::const_iterator&" << " end(" << tagS.listType() << "::const_iterator& p) const;" << std::endl; } hFile << std::endl << " void clear();" << std::endl << std::endl << " private:" << std::endl; for (iter = tagList.begin(); iter != tagList.end(); iter++) { XtString tagS((*iter)->getTagName()); parentList_t parentNames = parents[*iter]; if (parentNames.find("HDDM") == parentNames.end()) { hFile << " " << tagS.listType() << " null_" << tagS.plural() << ";" << std::endl; } } hFile << "};" << std::endl; } } /* Generate implementation code for data model classes */ void CodeBuilder::constructMethods(DOMElement* el) { // list type constructors std::vector::iterator iter; for (iter = tagList.begin(); iter != tagList.end(); iter++) { cFile << std::endl; DOMElement* tagEl = *iter; XtString tagS(tagEl->getTagName()); parentList_t parentNames = parents[tagEl]; parentList_t::iterator piter; for (piter = parentNames.begin(); piter != parentNames.end(); ++piter) { XtString nameS(piter->first); if (nameS == "HDDM") { cFile << tagS.listType() << "::" << tagS.listType() << "() {}" << std::endl; } else { cFile << tagS.listType() << "::" << tagS.listType() << "(const " << nameS.listType() << "* host, int index)" << std::endl << ": host_" << nameS.plural() << "(host)" << ", host_" << nameS << "(index)"; parentList_t::iterator ppiter; for (ppiter = parentNames.begin(); ppiter != parentNames.end(); ++ppiter) { XtString ptagS(ppiter->first); if (ptagS != "HDDM" && ptagS != nameS) { cFile << ",\n host_" << ptagS.plural() << "(0)" << ", host_" << ptagS << "(0)"; } } cFile << " {}" << std::endl; } } // list type member function create() cFile << tagS.simpleType() << "& " << tagS.listType() << "::create()" << std::endl << "{" << std::endl << " int index = size();" << std::endl << " " << tagS.simpleType() << " s(this,index);" << std::endl << " push_back(s);" << std::endl << " return back();" << std::endl << "}" << std::endl; // list iterator constructors cFile << tagS.listType() << "::iterator::iterator(const " << tagS.listType() << "::iterator& src)" << std::endl << ": list(src.list)"; for (piter = parentNames.begin(); piter != parentNames.end(); ++piter) { if (piter->first != "HDDM") { XtString ptagS(piter->first); cFile << ",\n " << ptagS << "(src." << ptagS << ")"; } } cFile << std::endl << "{" << std::endl << " (std::vector<" << tagS.simpleType() << ">::iterator)*this =" << std::endl << " (std::vector<" << tagS.simpleType() << ">::iterator)src;" << std::endl << "}" << std::endl; // list const_iterator constructors cFile << tagS.listType() << "::const_iterator::const_iterator(const " << tagS.listType() << "::iterator& src)" << std::endl << ": list(src.list)"; for (piter = parentNames.begin(); piter != parentNames.end(); ++piter) { if (piter->first != "HDDM") { XtString ptagS(piter->first); cFile << ",\n " << ptagS << "(src." << ptagS << ")"; } } cFile << std::endl << "{" << std::endl << " (std::vector<" << tagS.simpleType() << ">::const_iterator)*this =" << std::endl << " (std::vector<" << tagS.simpleType() << ">::iterator)src;" << std::endl << "}" << std::endl; cFile << tagS.listType() << "::const_iterator::const_iterator(const " << tagS.listType() << "::const_iterator& src)" << std::endl << ": list(src.list)"; for (piter = parentNames.begin(); piter != parentNames.end(); ++piter) { if (piter->first != "HDDM") { XtString ptagS(piter->first); cFile << ",\n " << ptagS << "(src." << ptagS << ")"; } } cFile << std::endl << "{" << std::endl << " (std::vector<" << tagS.simpleType() << ">::const_iterator)*this =" << std::endl << " (std::vector<" << tagS.simpleType() << ">::const_iterator)src;" << std::endl << "}" << std::endl; // list iterator assignment operator cFile << tagS.listType() << "::iterator& " << tagS.listType() << "::iterator::operator=(const " << tagS.listType() << "::iterator& src)" << std::endl << "{" << std::endl << " list = src.list;" << std::endl; for (piter = parentNames.begin(); piter != parentNames.end(); ++piter) { if (piter->first != "HDDM") { XtString ptagS(piter->first); cFile << " " << ptagS << " = src." << ptagS << ";" << std::endl; } } cFile << " (std::vector<" << tagS.simpleType() << ">::iterator)*this =" << std::endl << " (std::vector<" << tagS.simpleType() << ">::iterator)src;" << std::endl << " return *this;" << std::endl << "}" << std::endl; // list iterator pre-increment operator cFile << tagS.listType() << "::iterator& " << tagS.listType() << "::iterator::operator++()" << std::endl << "{" << std::endl << " ++(std::vector<" << tagS.simpleType() << ">::iterator)*this;" << std::endl; int hasParents = 0; for (piter = parentNames.begin(); piter != parentNames.end(); ++piter) { if (piter->first != "HDDM") { if (hasParents == 0) { cFile << " while (*this == list->end())" << std::endl << " {" << std::endl; } cFile << " " << ((++hasParents == 1)? "if" : "else if") << " (" << piter->first << " != " << piter->first << ".list->end())" << std::endl << " {" << std::endl << " ++" << piter->first << ";" << std::endl << " }" << std::endl; } } hasParents = 0; for (piter = parentNames.begin(); piter != parentNames.end(); ++piter) { if (piter->first != "HDDM") { cFile << " " << ((++hasParents == 1)? "if" : "else if") << " (" << piter->first << " != " << piter->first << ".list->end())" << std::endl << " {" << std::endl << " list = " << piter->first << "->" << tagS.plural() << ";" << std::endl << " (std::vector<" << tagS.simpleType() << ">::iterator)*this =" << std::endl << " " << piter->first << "->" << tagS.plural() << "->begin();" << std::endl << " }" << std::endl; } } if (hasParents) { cFile << " else" << std::endl << " {" << std::endl << " break;" << std::endl << " }" << std::endl << " }" << std::endl; } cFile << " return *this;" << std::endl << "}" << std::endl; // list iterator post-increment operator cFile << tagS.listType() << "::iterator " << tagS.listType() << "::iterator::operator++(int)" << std::endl << "{" << std::endl << " " << tagS.listType() << "::iterator " << "copy(*this);" << std::endl << " ++(*this);" << std::endl << " return copy;" << std::endl << "}" << std::endl; // list iterator pre-decrement operator cFile << tagS.listType() << "::iterator& " << tagS.listType() << "::iterator::operator--()" << std::endl << "{" << std::endl; hasParents = 0; for (piter = parentNames.end(); piter != parentNames.begin();) { --piter; XtString parS(piter->first); if (parS != "HDDM") { if (hasParents == 0) { cFile << " while (*this == list->begin())" << std::endl << " {" << std::endl; } cFile << " " << ((++hasParents == 1)? "if" : "else if") << " (" << parS << " != " << parS << ".list->begin())" << std::endl << " {" << std::endl << " list = (--" << piter->first << ")->" << tagS.plural() << ";" << std::endl << " (std::vector<" << tagS.simpleType() << ">::iterator)*this =" << std::endl << " " << parS << "->" << tagS.plural() << "->end();" << std::endl << " }" << std::endl; } } if (hasParents) { cFile << " else" << std::endl << " {" << std::endl << " break;" << std::endl << " }" << std::endl << " }" << std::endl; } cFile << " --(std::vector<" << tagS.simpleType() << ">::iterator)*this;" << std::endl << " return *this;" << std::endl << "}" << std::endl; // list iterator post-decrement operator cFile << tagS.listType() << "::iterator " << tagS.listType() << "::iterator::operator--(int)" << std::endl << "{" << std::endl << " " << tagS.listType() << "::iterator " << "copy(*this);" << std::endl << " --(*this);" << std::endl << " return copy;" << std::endl << "}" << std::endl; // list const_iterator assignment operators cFile << tagS.listType() << "::const_iterator& " << tagS.listType() << "::const_iterator::operator=(const " << tagS.listType() << "::iterator& src)" << std::endl << "{" << std::endl << " list = src.list;" << std::endl; for (piter = parentNames.begin(); piter != parentNames.end(); ++piter) { if (piter->first != "HDDM") { XtString ptagS(piter->first); cFile << " " << ptagS << " = src." << ptagS << ";" << std::endl; } } cFile << " (std::vector<" << tagS.simpleType() << ">::const_iterator)*this =" << std::endl << " (std::vector<" << tagS.simpleType() << ">::iterator)src;" << std::endl << " return *this;" << std::endl << "}" << std::endl; cFile << tagS.listType() << "::const_iterator& " << tagS.listType() << "::const_iterator::operator=(const " << tagS.listType() << "::const_iterator& src)" << std::endl << "{" << std::endl << " list = src.list;" << std::endl; for (piter = parentNames.begin(); piter != parentNames.end(); ++piter) { if (piter->first != "HDDM") { XtString ptagS(piter->first); cFile << " " << ptagS << " = src." << ptagS << ";" << std::endl; } } cFile << " (std::vector<" << tagS.simpleType() << ">::const_iterator)*this =" << std::endl << " (std::vector<" << tagS.simpleType() << ">::const_iterator)src;" << std::endl << " return *this;" << std::endl << "}" << std::endl; // list const_iterator pre-increment operator cFile << tagS.listType() << "::const_iterator& " << tagS.listType() << "::const_iterator::operator++()" << std::endl << "{" << std::endl << " ++(std::vector<" << tagS.simpleType() << ">::const_iterator)*this;" << std::endl; hasParents = 0; for (piter = parentNames.begin(); piter != parentNames.end(); ++piter) { if (piter->first != "HDDM") { if (hasParents == 0) { cFile << " while (*this == list->end())" << std::endl << " {" << std::endl; } cFile << " " << ((++hasParents == 1)? "if" : "else if") << " (" << piter->first << " != " << piter->first << ".list->end())" << std::endl << " {" << std::endl << " ++" << piter->first << ";" << std::endl << " }" << std::endl; } } hasParents = 0; for (piter = parentNames.begin(); piter != parentNames.end(); ++piter) { if (piter->first != "HDDM") { cFile << " " << ((++hasParents == 1)? "if" : "else if") << " (" << piter->first << " != " << piter->first << ".list->end())" << std::endl << " {" << std::endl << " list = " << piter->first << "->" << tagS.plural() << ";" << std::endl << " (std::vector<" << tagS.simpleType() << ">::const_iterator)*this =" << std::endl << " " << piter->first << "->" << tagS.plural() << "->begin();" << std::endl << " }" << std::endl; } } if (hasParents) { cFile << " else" << std::endl << " {" << std::endl << " break;" << std::endl << " }" << std::endl << " }" << std::endl; } cFile << " return *this;" << std::endl << "}" << std::endl; // list const_iterator post-increment operator cFile << tagS.listType() << "::const_iterator " << tagS.listType() << "::const_iterator::operator++(int)" << std::endl << "{" << std::endl << " " << tagS.listType() << "::const_iterator " << "copy(*this);" << std::endl << " ++(*this);" << std::endl << " return copy;" << std::endl << "}" << std::endl; // list const_iterator pre-decrement operator cFile << tagS.listType() << "::const_iterator& " << tagS.listType() << "::const_iterator::operator--()" << std::endl << "{" << std::endl; hasParents = 0; for (piter = parentNames.end(); piter != parentNames.begin();) { --piter; XtString parS(piter->first); if (parS != "HDDM") { if (hasParents == 0) { cFile << " while (*this == list->begin())" << std::endl << " {" << std::endl; } cFile << " " << ((++hasParents == 1)? "if" : "else if") << " (" << parS << " != " << parS << ".list->begin())" << std::endl << " {" << std::endl << " list = (--" << piter->first << ")->" << tagS.plural() << ";" << std::endl << " (std::vector<" << tagS.simpleType() << ">::const_iterator)*this =" << std::endl << " " << parS << "->" << tagS.plural() << "->end();" << std::endl << " }" << std::endl; } } if (hasParents) { cFile << " else" << std::endl << " {" << std::endl << " break;" << std::endl << " }" << std::endl << " }" << std::endl; } cFile << " --(std::vector<" << tagS.simpleType() << ">::const_iterator)*this;" << std::endl << " return *this;" << std::endl << "}" << std::endl; // list const_iterator post-decrement operator cFile << tagS.listType() << "::const_iterator " << tagS.listType() << "::const_iterator::operator--(int)" << std::endl << "{" << std::endl << " " << tagS.listType() << "::const_iterator " << "copy(*this);" << std::endl << " --(*this);" << std::endl << " return copy;" << std::endl << "}" << std::endl << std::endl; // list element constructor DOMNamedNodeMap* varList = tagEl->getAttributes(); int varCount = varList->getLength(); cFile << tagS.simpleType() << "::" << tagS.simpleType() << "(const " << tagS.listType() << "* host, int index)"; int first=0; for (int v = 0; v < varCount; v++) { DOMNode* var = varList->item(v); XtString typeS(var->getNodeValue()); XtString nameS(var->getNodeName()); if (typeS == "string" || typeS == "anyURI") { cFile << ((first++ == 0)? "\n: " : ",\n ") << nameS << "(\"\")"; } else if (typeS == "int" || typeS == "long" || typeS == "float" || typeS == "double" || typeS == "boolean") { cFile << ((first++ == 0)? "\n: " : ",\n ") << nameS << "(0)"; } else if (typeS == "Particle_t") { cFile << ((first++ == 0)? "\n: " : ",\n ") << nameS << "(Unknown)"; } } cFile << std::endl << "{" << std::endl; DOMNodeList* contList = tagEl->getChildNodes(); for (int c = 0; c < contList->getLength(); c++) { DOMNode* cont = contList->item(c); short ctype = cont->getNodeType(); if (ctype == DOMNode::ELEMENT_NODE) { DOMElement* contEl = (DOMElement*) cont; XtString cnameS(contEl->getTagName()); cFile << " " << cnameS.plural() << " = new " << cnameS.listType() << "(host, index);" << std::endl; } } cFile << "}" << std::endl; // list element destructor if (contList->getLength() > 0) { cFile << tagS.simpleType() << "::" << "~" << tagS.simpleType() << "()" << std::endl << "{" << std::endl; for (int c = 0; c < contList->getLength(); c++) { DOMNode* cont = contList->item(c); short ctype = cont->getNodeType(); if (ctype == DOMNode::ELEMENT_NODE) { DOMElement* contEl = (DOMElement*) cont; XtString cnameS(contEl->getTagName()); cFile << " delete " << cnameS.plural() << ";" << std::endl; } } cFile << "}" << std::endl; } // list element lookup member functions for (int c = 0; c < contList->getLength(); c++) { DOMNode* cont = contList->item(c); short ctype = cont->getNodeType(); if (ctype == DOMNode::ELEMENT_NODE) { DOMElement* contEl = (DOMElement*) cont; XtString cnameS(contEl->getTagName()); cFile << cnameS.simpleType() << "* " << tagS.simpleType() << "::" << cnameS; XtString repS = contEl->getAttribute(X("maxOccurs")); int rep = (repS == "unbounded")? 9999 : atoi(S(repS)); cFile << ((rep > 1)? "(int n)" : "()") << std::endl << "{" << std::endl; if (rep > 1) { cFile << " int max = " << cnameS.plural() << "->size()-1;" << std::endl << " if (n < 0 || n > max)" << std::endl << " {" << std::endl << " std::stringstream err;" << std::endl << " err << \"" << tagS.simpleType() << "::" << cnameS << "(n)" << " called with n=\" << n" << std::endl << " << \", valid range is [\";" << std::endl << " if (max >= 0)" << std::endl << " {" << std::endl << " err << \"0,\" << max;" << std::endl << " }" << std::endl << " err << \"]\";" << std::endl << " throw err.str();" << std::endl << " }" << std::endl << " return &(*" << cnameS.plural() << ")[n];" << std::endl << "}" << std::endl; } else { cFile << " if (" << cnameS.plural() << "->size() != 1)" << std::endl << " {" << std::endl << " std::stringstream err;" << std::endl << " err << \"" << tagS.simpleType() << "::" << cnameS << "()" << " expecting one entry,\"" << std::endl << " << \" found \" << " << cnameS.plural() << "->size();" << std::endl << " throw err.str();" << std::endl << " }" << std::endl << " return &(*" << cnameS.plural() << ")[0];" << std::endl << "}" << std::endl; } } } } // Record_t class constructor XtString tagS("record"); DOMNamedNodeMap* varList = el->getAttributes(); int varCount = varList->getLength(); cFile << std::endl << "Record_t::Record_t()"; int first=0; for (iter = tagList.begin(); iter != tagList.end(); iter++) { XtString nameS((*iter)->getTagName()); parentList_t parentNames = parents[*iter]; if (parentNames.find("HDDM") == parentNames.end()) { XtString parentS(parentNames.begin()->first); cFile << ((first++ == 0)? "\n: " : ",\n ") << "null_" << nameS.plural() << "((" << parentS.listType() << "*)0,0)"; } } for (int v = 0; v < varCount; v++) { DOMNode* var = varList->item(v); XtString typeS(var->getNodeValue()); XtString nameS(var->getNodeName()); if (typeS == "string" || typeS == "anyURI") { cFile << ((first++ == 0)? "\n: " : ",\n ") << nameS << "(\"\")"; } else if (typeS == "int" || typeS == "long" || typeS == "float" || typeS == "double" || typeS == "boolean") { cFile << ((first++ == 0)? "\n: " : ",\n ") << nameS << "(0)"; } else if (typeS == "Particle_t") { cFile << ((first++ == 0)? "\n: " : ",\n ") << nameS << "(Unknown)"; } } cFile << std::endl << "{" << std::endl; DOMNodeList* contList = el->getChildNodes(); for (int c = 0; c < contList->getLength(); c++) { DOMNode* cont = contList->item(c); short ctype = cont->getNodeType(); if (ctype == DOMNode::ELEMENT_NODE) { DOMElement* contEl = (DOMElement*) cont; XtString cnameS(contEl->getTagName()); cFile << " " << cnameS.plural() << " = new " << cnameS.listType() << "();" << std::endl; } } cFile << "}" << std::endl; // Record_t class destructor cFile << "Record_t::~Record_t()" << std::endl << "{" << std::endl; for (int c = 0; c < contList->getLength(); c++) { DOMNode* cont = contList->item(c); short ctype = cont->getNodeType(); if (ctype == DOMNode::ELEMENT_NODE) { DOMElement* contEl = (DOMElement*) cont; XtString cnameS(contEl->getTagName()); cFile << " delete " << cnameS.plural() << ";" << std::endl; } } cFile << "}" << std::endl; // Record_t member function clear() cFile << "void Record_t::clear()" << std::endl << "{" << std::endl; for (int c = 0; c < contList->getLength(); c++) { DOMNode* cont = contList->item(c); short ctype = cont->getNodeType(); if (ctype == DOMNode::ELEMENT_NODE) { DOMElement* contEl = (DOMElement*) cont; XtString cnameS(contEl->getTagName()); cFile << " " << cnameS.plural() << "->clear();" << std::endl; } } cFile << "}" << std::endl; // member lookup functions for (int c = 0; c < contList->getLength(); c++) { DOMNode* cont = contList->item(c); short ctype = cont->getNodeType(); if (ctype == DOMNode::ELEMENT_NODE) { DOMElement* contEl = (DOMElement*) cont; XtString cnameS(contEl->getTagName()); cFile << cnameS.simpleType() << "* " << tagS.simpleType() << "::" << cnameS; XtString repS = contEl->getAttribute(X("maxOccurs")); int rep = (repS == "unbounded")? 9999 : atoi(S(repS)); cFile << ((rep > 1)? "(int n)" : "()") << std::endl << "{" << std::endl; if (rep > 1) { cFile << " int max = " << cnameS.plural() << "->size()-1;" << std::endl << " if (n < 0 || n > max)" << std::endl << " {" << std::endl << " std::stringstream err;" << std::endl << " err << \"" << tagS.simpleType() << "::" << cnameS << "(n)" << " called with n=\" << n" << std::endl << " << \", valid range is [\";" << std::endl << " if (max >= 0)" << std::endl << " {" << std::endl << " err << \"0,\" << max;" << std::endl << " }" << std::endl << " err << \"]\";" << std::endl << " throw err.str();" << std::endl << " }" << std::endl << " return &(*" << cnameS.plural() << ")[n];" << std::endl << "}" << std::endl; } else { cFile << " if (" << cnameS.plural() << "->size() != 1)" << std::endl << " {" << std::endl << " std::stringstream err;" << std::endl << " err << \"" << tagS.simpleType() << "::" << cnameS << "()" << " expecting one entry,\"" << std::endl << " << \" found \" << " << cnameS.plural() << "->size();" << std::endl << " throw err.str();" << std::endl << " }" << std::endl << " return &(*" << cnameS.plural() << ")[0];" << std::endl << "}" << std::endl; } } } // iterator creation member functions for Record_t cFile << std::endl; for (iter = tagList.begin(); iter != tagList.end(); iter++) { DOMElement* tagEl = *iter; XtString nameS(tagEl->getTagName()); parentList_t parentNames = parents[tagEl]; if (parentNames.find("HDDM") != parentNames.end()) { cFile << nameS.listType() << "::iterator& Record_t::begin(" << nameS.listType() << "::iterator& p)" << std::endl << "{" << std::endl << " p.list = " << nameS.plural() << ";" << std::endl << " (std::vector<" << nameS.simpleType() << ">::iterator)p = " << nameS.plural() << "->begin();" << std::endl << " return p;" << std::endl << "}" << std::endl; cFile << nameS.listType() << "::iterator& Record_t::end(" << nameS.listType() << "::iterator& p)" << std::endl << "{" << std::endl << " p.list = " << nameS.plural() << ";" << std::endl << " (std::vector<" << nameS.simpleType() << ">::iterator)p = " << nameS.plural() << "->end();" << std::endl << " return p;" << std::endl << "}" << std::endl; cFile << nameS.listType() << "::const_iterator& Record_t::begin(" << nameS.listType() << "::const_iterator& p) const"<< std::endl << "{" << std::endl << " p.list = " << nameS.plural() << ";" << std::endl << " (std::vector<" << nameS.simpleType() << ">::const_iterator)p = " << nameS.plural() << "->begin();" << std::endl << " return p;" << std::endl << "}" << std::endl; cFile << nameS.listType() << "::const_iterator& Record_t::end(" << nameS.listType() << "::const_iterator& p) const"<< std::endl << "{" << std::endl << " p.list = " << nameS.plural() << ";" << std::endl << " (std::vector<" << nameS.simpleType() << ">::const_iterator)p = " << nameS.plural() << "->end();" << std::endl << " return p;" << std::endl << "}" << std::endl; continue; } cFile << nameS.listType() << "::iterator& Record_t::begin(" << nameS.listType() << "::iterator& p)" << std::endl << "{" << std::endl << " " << nameS.listType() << "::iterator it;" << std::endl; parentList_t::iterator piter; for (piter = parentNames.begin(); piter != parentNames.end(); ++piter) { cFile << " p." << piter->first << " = begin(it." << piter->first << ");" << std::endl; } cFile << " p.list = &null_" << nameS.plural() << ";" << std::endl << " (std::vector<" << nameS.simpleType() << ">::iterator)p = p.list->begin();" << std::endl << " --(std::vector<" << nameS.simpleType() << ">::iterator)p;" << std::endl << " --p." << parentNames.begin()->first << ";" << std::endl << " return ++p;" << std::endl << "}" << std::endl; cFile << nameS.listType() << "::iterator& Record_t::end(" << nameS.listType() << "::iterator& p)" << std::endl << "{" << std::endl << " " << nameS.listType() << "::iterator it;" << std::endl; for (piter = parentNames.begin(); piter != parentNames.end(); ++piter) { cFile << " p." << piter->first << " = end(it." << piter->first << ");" << std::endl; } cFile << " p.list = &null_" << nameS.plural() << ";" << std::endl << " (std::vector<" << nameS.simpleType() << ">::iterator)p = p.list->end();" << std::endl << " --p;" << std::endl << " return ++p;" << std::endl << "}" << std::endl; cFile << nameS.listType() << "::const_iterator& Record_t::begin(" << nameS.listType() << "::const_iterator& p) const" << std::endl << "{" << std::endl << " " << nameS.listType() << "::const_iterator it;" << std::endl; for (piter = parentNames.begin(); piter != parentNames.end(); ++piter) { cFile << " p." << piter->first << " = begin(it." << piter->first << ");" << std::endl; } cFile << " p.list = &null_" << nameS.plural() << ";" << std::endl << " (std::vector<" << nameS.simpleType() << ">::const_iterator)p = p.list->begin();" << std::endl << " --(std::vector<" << nameS.simpleType() << ">::const_iterator)p; " << std::endl << " --p." << parentNames.begin()->first << ";" << std::endl << " return ++p;" << std::endl << "}" << std::endl; cFile << nameS.listType() << "::const_iterator& Record_t::end(" << nameS.listType() << "::const_iterator& p) const" << std::endl << "{" << std::endl << " " << nameS.listType() << "::const_iterator it;" << std::endl; for (piter = parentNames.begin(); piter != parentNames.end(); ++piter) { cFile << " p." << piter->first << " = end(it." << piter->first << ");" << std::endl; } cFile << " p.list = &null_" << nameS.plural() << ";" << std::endl << " (std::vector<" << nameS.simpleType() << ">::const_iterator)p = p.list->end();" << std::endl << " --p;" << std::endl << " return ++p;" << std::endl << "}" << std::endl; } } /* Generate methods for unpacking binary stream into classes */ void CodeBuilder::constructUnpackers(DOMElement* el) { cFile << std::endl; std::vector::iterator iter; for (iter = tagList.begin(); iter != tagList.end(); iter++) { DOMElement* tagEl = *iter; XtString tagS(tagEl->getTagName()); XtString listType = tagS.listType(); XtString simpleType = tagS.simpleType(); cFile << std::endl << "static "; XtString tagType; XtString repS = tagEl->getAttribute(X("maxOccurs")); int rep = (repS == "unbounded")? 9999 : atoi(S(repS)); if (rep > 1) { tagType = tagS.listType(); } else { tagType = tagS.simpleType(); } XtString tagT(tagType); tagT.erase(tagT.rfind('_')); cFile << tagType << "* unpack_" << tagT << "(XDR* xdrs, popNode* pop)" << std::endl << "{" << std::endl << " " << tagType << "* this1 = HDDM_NULL;" << std::endl << " unsigned int size;" << std::endl << " if (! xdr_u_int(xdrs,&size))" << std::endl << " {" << std::endl << " return this1;" << std::endl << " }" << std::endl << " else if (size > 0)" << std::endl << " {" << std::endl << " int start = xdr_getpos(xdrs);" << std::endl; if (rep > 1) { cFile << " int m;" << std::endl << " unsigned int mult;" << std::endl << " xdr_u_int(xdrs,&mult);" << std::endl << " this1 = make_" << tagT << "(mult);" << std::endl << " this1->mult = mult;" << std::endl << " for (m = 0; m < mult; m++ )" << std::endl << " {" << std::endl; } else { cFile << " this1 = make_" << tagT << "();" << std::endl << " {" << std::endl; } int hasContents = 0; DOMNodeList* contList = tagEl->getChildNodes(); for (int c = 0; c < contList->getLength(); c++) { DOMNode* cont = contList->item(c); short type = cont->getNodeType(); if (type == DOMNode::ELEMENT_NODE) { hasContents = 1; DOMElement* contEl = (DOMElement*) cont; XtString nameS(contEl->getTagName()); XtString reS(contEl->getAttribute(X("maxOccurs"))); int re = (reS == "unbounded")? 9999 : atoi(S(reS)); cFile << " int p;" << std::endl << " void* (*ptr) = (void**) &this1->" << ((rep > 1) ? "in[m]." : "" ) << ((re > 1) ? nameS.plural() : nameS) << ";" << std::endl; break; } } DOMNamedNodeMap* attList = tagEl->getAttributes(); for (int a = 0; a < attList->getLength(); a++) { DOMNode* att = attList->item(a); XtString typeS(att->getNodeValue()); XtString nameS(att->getNodeName()); XtString nameStr(nameS); if (rep > 1) { nameStr = "in[m]." + nameS; } if (typeS == "int") { cFile << " xdr_int(xdrs,&this1->" << nameStr << ");" << std::endl; } else if (typeS == "long") { cFile << "#ifndef XDR_LONGLONG_MISSING" << std::endl << " xdr_longlong_t(xdrs,&this1->" << nameStr << ");" << std::endl << "#else" << std::endl << " {" << std::endl << " int* " << nameStr << "_ = " << "(int*)&this1->" << nameStr << ";" << std::endl << "# if __BIG_ENDIAN__" << std::endl << " xdr_int(xdrs,&" << nameStr << "_[0]);" << std::endl << " xdr_int(xdrs,&" << nameStr << "_[1]);" << std::endl << "# else" << std::endl << " xdr_int(xdrs,&" << nameStr << "_[1]);" << std::endl << " xdr_int(xdrs,&" << nameStr << "_[0]);" << std::endl << "# endif" << std::endl << " }" << std::endl << "#endif" << std::endl; } else if (typeS == "float") { cFile << " xdr_float(xdrs,&this1->" << nameStr << ");" << std::endl; } else if (typeS == "double") { cFile << " xdr_double(xdrs,&this1->" << nameStr << ");" << std::endl; } else if (typeS == "boolean") { cFile << " xdr_bool(xdrs,&this1->" << nameStr << ");" << std::endl; } else if (typeS == "Particle_t") { cFile << " xdr_int(xdrs,(int*)&this1->" << nameStr << ");" << std::endl; } else if (typeS == "string") { cFile << " xdr_string(xdrs,&this1->" << nameStr << ", 1000000);" << std::endl; } else if (typeS == "anyURI") { cFile << " xdr_string(xdrs,&this1->" << nameStr << ", 1000000);" << std::endl; } else { /* ignore attributes with unrecognized values */ } } if (hasContents) { cFile << " for (p = 0; p < pop->popListLength; p++)" << std::endl << " {" << std::endl << " popNode* pnode = pop->popList[p];" << std::endl << " if (pnode)" << std::endl << " {" << std::endl << " int kid = pnode->inParent;" << std::endl << " ptr[kid] = pnode->unpacker(xdrs,pnode);" << std::endl << " }" << std::endl << " else" << std::endl << " {" << std::endl << " unsigned int skip;" << std::endl << " xdr_u_int(xdrs,&skip);" << std::endl << " xdr_setpos(xdrs,xdr_getpos(xdrs)+skip);" << std::endl << " }" << std::endl << " }" << std::endl; } cFile << " }" << std::endl << " xdr_setpos(xdrs,start+size);" << std::endl << " }" << std::endl << " return this1;" << std::endl << "}" << std::endl; } } /* Generate methods to read from binary stream into classes */ void CodeBuilder::constructIOstreams(DOMElement* el) { hFile << std::endl << "class istream" << std::endl << "{" << std::endl << " public:" << std::endl << " istream(std::istream& istr);" << std::endl << " istream(std::streambuf* sb);" << std::endl << " istream& operator>>(Record_t& record);" << std::endl << " private:" << std::endl << " xstream::xdr::istream xstr;" << std::endl << " std::string documentString;" << std::endl << " class codon;" << std::endl << " class codon {" << std::endl << " void* (*unpacker)();" << std::endl << " int inParent;" << std::endl << " std::vector sequence;" << std::endl << " };" << std::endl << " std::vector genome;" << std::endl << " void* synthesize(void* p, std::vector sequence);"<< std::endl; std::vector::iterator iter; for (iter = tagList.begin(); iter != tagList.end(); ++iter) { XtString nameS((*iter)->getTagName()); XtString typeS = nameS.listType(); XtString shortS(typeS); shortS.erase(shortS.rfind('_')); hFile << " " << typeS << "* unpack" << shortS << "(std::vector gene);" << std::endl; } hFile << "};" << std::endl; hFile << std::endl << "class ostream" << std::endl << "{" << std::endl << " public:" << std::endl << " ostream(std::ostream& ostr);" << std::endl << " ostream(std::streambuf* sb);" << std::endl << " ostream& operator<<(Record_t& record);" << std::endl << " private:" << std::endl << " xstream::xdr::ostream xstr;" << std::endl << " std::string documentString;" << std::endl; for (iter = tagList.begin(); iter != tagList.end(); ++iter) { XtString nameS((*iter)->getTagName()); XtString typeS = nameS.listType(); XtString shortS(typeS); shortS.erase(shortS.rfind('_')); hFile << " int pack" << shortS << "(" << typeS << "* p);" << std::endl; } hFile << "};" << std::endl; XtString topS(el->getTagName()); XtString topType = topS.simpleType(); XtString topT(topType); topT.erase(topT.rfind('_')); cFile << std::endl << topType << "* read_" << topT << "(" << classPrefix << "_iostream_t* fp" << ")" << std::endl << "{" << std::endl << " " << topType << "* nextEvent = " << "unpack_" << topT << "(fp->xdrs,fp->popTop);" << std::endl << " return (nextEvent == HDDM_NULL)? 0 : nextEvent;" << std::endl << "}" << std::endl; } /* Generate streamers for packing c-structures onto a binary stream * and deleting them from memory when output is complete */ void CodeBuilder::constructPackers(DOMElement* el) { cFile << std::endl; std::vector::iterator iter; for (iter = tagList.begin(); iter != tagList.end(); iter++) { XtString tagS((*iter)->getTagName()); XtString listType = tagS.listType(); XtString simpleType = tagS.simpleType(); cFile << "static "; XtString tagType; XtString repS(el->getAttribute(X("maxOccurs"))); int rep = (repS == "unbounded")? 9999 : atoi(S(repS)); if (rep > 1) { tagType = listType; } else { tagType = simpleType; } XtString tagT(tagType); tagT.erase(tagT.rfind('_')); cFile << "int pack_" << tagT << "(XDR* xdrs, " << tagType << "* this1);" << std::endl; } for (iter = tagList.begin(); iter != tagList.end(); iter++) { XtString tagS((*iter)->getTagName()); XtString listType = tagS.listType(); XtString simpleType = tagS.simpleType(); cFile << std::endl << "static "; XtString tagType; XtString repS(el->getAttribute(X("maxOccurs"))); int rep = (repS == "unbounded")? 9999 : atoi(S(repS)); if (rep > 1) { tagType = listType; } else { tagType = simpleType; } XtString tagT(tagType); tagT.erase(tagT.rfind('_')); cFile << "int pack_" << tagT << "(XDR* xdrs, " << tagType << "* this1)" << std::endl << "{" << std::endl << " int m;" << std::endl << " unsigned int size=0;" << std::endl << " int base,start,end;" << std::endl << " base = xdr_getpos(xdrs);" << std::endl << " xdr_u_int(xdrs,&size);" << std::endl << " start = xdr_getpos(xdrs);" << std::endl << std::endl; if (rep > 1) { cFile << " xdr_u_int(xdrs,&this1->mult);" << std::endl << " for (m = 0; m < this1->mult; m++)" << std::endl << " {" << std::endl; } else { cFile << " m = 0; /* avoid warnings from -Wall */" << std::endl << " {" << std::endl; } DOMNamedNodeMap* attList = el->getAttributes(); for (int a = 0; a < attList->getLength(); a++) { DOMNode* att = attList->item(a); XtString typeS(att->getNodeValue()); XtString nameS(att->getNodeName()); XtString nameStr(nameS); if (rep > 1) { nameStr = "in[m]." + nameS; } if (typeS == "int") { cFile << " xdr_int(xdrs,&this1->" << nameStr << ");" << std::endl; } if (typeS == "long") { cFile << "#ifndef XDR_LONGLONG_MISSING" << std::endl << " xdr_longlong_t(xdrs,&this1->" << nameStr << ");" << std::endl << "#else" << std::endl << " {" << std::endl << " int* " << nameStr << "_ = " << "(int*)&this1->" << nameStr << ";" << std::endl << "# if __BIG_ENDIAN__" << std::endl << " xdr_int(xdrs,&" << nameStr << "_[0]);" << std::endl << " xdr_int(xdrs,&" << nameStr << "_[1]);" << std::endl << "# else" << std::endl << " xdr_int(xdrs,&" << nameStr << "_[1]);" << std::endl << " xdr_int(xdrs,&" << nameStr << "_[0]);" << std::endl << "# endif" << std::endl << " }" << std::endl << "#endif" << std::endl; } else if (typeS == "float") { cFile << " xdr_float(xdrs,&this1->" << nameStr << ");" << std::endl; } else if (typeS == "double") { cFile << " xdr_double(xdrs,&this1->" << nameStr << ");" << std::endl; } else if (typeS == "boolean") { cFile << " xdr_bool(xdrs,&this1->" << nameStr << ");" << std::endl; } else if (typeS == "Particle_t") { cFile << " xdr_int(xdrs,(int*)&this1->" << nameStr << ");" << std::endl; } else if (typeS == "string") { cFile << " xdr_string(xdrs,&this1->" << nameStr << ", 1000000);" << std::endl; } else if (typeS == "anyURI") { cFile << " xdr_string(xdrs,&this1->" << nameStr << ", 1000000);" << std::endl; } else { /* ignore attributes with unrecognized values */ } } DOMNodeList* contList = el->getChildNodes(); for (int c = 0; c < contList->getLength(); c++) { DOMNode* cont = contList->item(c); short type = cont->getNodeType(); if (type == DOMNode::ELEMENT_NODE) { DOMElement* contEl = (DOMElement*) cont; XtString nameS(contEl->getTagName()); XtString reS(contEl->getAttribute(X("maxOccurs"))); int re = (reS == "unbounded")? 9999 : atoi(S(reS)); XtString contType; if (re > 1) { contType = nameS.listType(); } else { contType = nameS.simpleType(); } XtString contT(contType); contT.erase(contT.rfind('_')); cFile << " if (this1->" << ((rep > 1)? "in[m]." : "") << ((re > 1)? nameS.plural(): nameS) << " != (" << contType << "*)&hddm_nullTarget)" << std::endl << " {" << std::endl << " pack_" << contT << "(xdrs,this1->" << ((rep > 1)? "in[m]." : "") << ((re > 1)? nameS.plural() : nameS) << ");" << std::endl << " }" << std::endl << " else" << std::endl << " {" << std::endl << " int zero=0;" << std::endl << " xdr_int(xdrs,&zero);" << std::endl << " }" << std::endl; } } cFile << " }" << std::endl << " FREE(this1);" << std::endl << " end = xdr_getpos(xdrs);" << std::endl << " xdr_setpos(xdrs,base);" << std::endl << " size = end-start;" << std::endl << " xdr_u_int(xdrs,&size);" << std::endl << " xdr_setpos(xdrs,end);" << std::endl << " return size;" << std::endl << "}" << std::endl; } } /* Generate methods that match up corresponding elements between * the class members and the data model that appears on the input * binary stream. If successful, these routines build a hierarchical * structure (the "pop tree") that gives directions to the unpackers. * * The matching rules are as follows: * * 1) The attribute list for any given tag must be identical in content * and order wherever it appears, otherwise there is a collision. * * 2) The content list for any given tag must be internally consistent * within each model, but there are no requirements for agreement * between the c-structures and the binary stream models. Only the * contents which appear in both models will be unpacked, however. */ void CodeBuilder::writeMatcher() { cFile << std::endl << "static int getTag(char* d, char* tag)" << std::endl << "{" << std::endl << " int level;" << std::endl << " char* token;" << std::endl << " char line[500];" << std::endl << " strncpy(line,d,500);" << std::endl << " line[499] = 0;" << std::endl << " level = index(line,'<')-line;" << std::endl << " if (level < 500 &&" << std::endl << " (token = strtok(line+level+1,\" >\")))" << std::endl << " {" << std::endl << " strncpy(tag,token,500);" << std::endl << " return level/2;" << std::endl << " }" << std::endl << " return -1;" << std::endl << "}" << std::endl << std::endl << "static char* getEndTag(char* d, char* tag)" << std::endl << "{" << std::endl << " char line[500];" << std::endl << " char endTag[510];" << std::endl << " strncpy(line,d,500);" << std::endl << " line[499] = 0;" << std::endl << " if (strstr(strtok(line,\"\\n\"),\"/>\") == 0)" << std::endl << " {" << std::endl << " sprintf(endTag,\"\",tag);" << std::endl << " }" << std::endl << " else" << std::endl << " {" << std::endl << " strcpy(endTag,\"/>\");" << std::endl << " }" << std::endl << " return strstr(d,endTag);" << std::endl << "}" << std::endl << std::endl << "static void collide(char* b, char* c)" << std::endl << "{" << std::endl << " char btag[500];" << std::endl << " getTag(b,btag);" << std::endl << " b = index(b,'<');" << std::endl << " c = index(c,'<');" << std::endl << " *(index(b,'\\n')) = 0;" << std::endl << " *(index(c,'\\n')) = 0;" << std::endl << " fprintf(stderr,\"HDDM warning: \");" << std::endl << " fprintf(stderr,\"tag %s in input file \", btag);" << std::endl << " fprintf(stderr,\"does not match c header hddm_" << classPrefix << ".h\\n\");" << std::endl << " fprintf(stderr,\" input file: %s\\n\", b);" << std::endl << " fprintf(stderr,\" c header: %s\\n\", c);" << std::endl << " fprintf(stderr,\" === Tag %s will be ignored,\", btag);" << std::endl << " fprintf(stderr,\" rebuild to cure the problem ===\\n\");" << std::endl << " *(index(b,0)) = '\\n';" << std::endl << " *(index(c,0)) = '\\n';" << std::endl << "}" << std::endl << std::endl << "static popNode* matches(char* b, char* c)" << std::endl << "{" << std::endl << " char btag[500];" << std::endl << " char ctag[500];" << std::endl << " int blevel, clevel;" << std::endl << " int ptrSeqNo = 0;" << std::endl << " blevel = getTag(b,btag);" << std::endl << " while ((clevel = getTag(c,ctag)) == blevel)" << std::endl << " {" << std::endl << " if " << "((clevel == blevel) && (strcmp(ctag,btag) == 0))" << std::endl << " {" << std::endl << " popNode* this1 = " << "(popNode*)malloc(sizeof(popNode));" << std::endl << " int len = index(c+1,'\\n') - c;" << std::endl << " if (strncmp(c,b,len) != 0)" << std::endl << " {" << std::endl << " collide(b,c);" << std::endl << " return 0;" << std::endl << " }" << std::endl; std::vector::iterator iter; for (iter = tagList.begin(); iter != tagList.end(); iter++) { XtString tagS((*iter)->getTagName()); XtString repS((*iter)->getAttribute(X("maxOccurs"))); int rep = (repS == "unbounded")? 9999 : atoi(S(repS)); XtString tagType; if (rep > 1) { tagType = tagS.listType(); } else { tagType = tagS.simpleType(); } XtString tagT(tagType); tagT.erase(tagT.rfind('_')); cFile << " else if " << "(strcmp(btag,\"" << tagS << "\") == 0)" << std::endl << " {" << std::endl << " this1->unpacker = " << "(void*(*)(XDR*,popNode*))" << "unpack_" << tagT << ";" << std::endl << " }" << std::endl; } cFile << " this1->inParent = ptrSeqNo;" << std::endl << " this1->popListLength = 0;" << std::endl << " c = index(c+1,'\\n');" << std::endl << " b = index(b+1,'\\n');" << std::endl << " while (getTag(b,btag) > blevel)" << std::endl << " {" << std::endl << " this1->popList[this1->popListLength++] = matches(b,c);" << std::endl << " if (this1->popListLength > " << 999 << ")" << std::endl << " {" << std::endl << " fprintf(stderr," << "\"hddm error - posList overflow.\\n\");" << std::endl << " fprintf(stderr," << "\"Increase MAX_POPLIST_LENGTH and recompile.\\n\");" << std::endl << " exit(9);" << std::endl << " }" << std::endl << " b = getEndTag(b,btag);" << std::endl << " b = index(b+1,'\\n');" << std::endl << " }" << std::endl << " return this1;" << std::endl << " }" << std::endl << " else" << std::endl << " {" << std::endl << " c = getEndTag(c,ctag);" << std::endl << " c = index(c+1,'\\n');" << std::endl << " ++ptrSeqNo;" << std::endl << " }" << std::endl << " }" << std::endl << " return 0;" << std::endl << "}" << std::endl; } /* Generate code to open a hddm file for reading */ #if 0 void CodeBuilder::constructOperators(DOMElement* el) { XtString tagS(el->getTagName()); XtString tagType = tagS.simpleType(); XtString tagT(tagType); tagT.erase(tagT.rfind('_')); writeMatcher(); cFile << std::endl << classPrefix << "_iostream_t* " << "open_" << tagT << "(char* filename)" << std::endl << "{" << std::endl << " " << classPrefix << "_iostream_t* fp = " << "(" << classPrefix << "_iostream_t*)" << "malloc(sizeof(" << classPrefix << "_iostream_t));" << std::endl << " char* p;" << std::endl << " char* head;" << std::endl << " if (filename)" << std::endl << " {" << std::endl << " fp->fd = fopen(filename,\"r\");" << std::endl << " }" << std::endl << " else" << std::endl << " {" << std::endl << " fp->fd = fdopen(0,\"r\");" << std::endl << " }" << std::endl << " if (fp->fd == 0)" << std::endl << " {" << std::endl << " free(fp);" << std::endl << " return 0;" << std::endl << " }" << std::endl << " fp->iomode = HDDM_STREAM_INPUT;" << std::endl << " head = (char*)malloc(1000000);" << std::endl << " *head = 0;" << std::endl << " for (p = head;" << std::endl << " strstr(head,\"\") == 0;" << std::endl << " p += strlen(p))" << std::endl << " {" << std::endl << " if (p-head < 999000)" << std::endl << " {" << std::endl << " fgets(p,1000,fp->fd);" << std::endl << " }" << std::endl << " else" << std::endl << " {" << std::endl << " break;" << std::endl << " }" << std::endl << " }" << std::endl << " fp->popTop = matches(head,HDDM_" << classPrefix << "_DocumentString);" << std::endl << " free(head);" << std::endl << " if (fp->popTop->popListLength == 0)" << std::endl << " {" << std::endl << " fprintf(stderr,\"HDDM Error: \");" << std::endl << " fprintf(stderr,\"input template model \");" << std::endl << " fprintf(stderr,\"does not match c header.\");"<< std::endl << " fprintf(stderr,\" Please recompile.\\n\");" << std::endl << " exit(9);" << std::endl << " }" << std::endl << " fp->filename = " << "(char*)malloc(strlen(filename) + 1);" << std::endl << " strcpy(fp->filename,filename);" << std::endl << " fp->xdrs = (XDR*)malloc(sizeof(XDR));" << std::endl << " xdrstdio_create(fp->xdrs,fp->fd,XDR_DECODE);" << std::endl << " return fp;" << std::endl << "}" << std::endl; } /* Generate the code to open a hddm file for writing */ void CodeBuilder::constructInitFunc(DOMElement* el) { XtString tagS(el->getTagName()); XtString tagType = tagS.simpleType(); XtString tagT(tagType); tagT.erase(tagT.rfind('_')); cFile << std::endl << classPrefix << "_iostream_t* " << "init_" << tagT << "(char* filename)" << std::endl << "{" << std::endl << " int len;" << std::endl << " char* head;" << std::endl << " " << classPrefix << "_iostream_t* fp = " << "(" << classPrefix << "_iostream_t*)" << "malloc(sizeof(" << classPrefix << "_iostream_t));" << std::endl << " if (filename)" << std::endl << " {" << std::endl << " fp->fd = fopen(filename,\"w\");" << std::endl << " }" << std::endl << " else" << std::endl << " {" << std::endl << " fp->fd = fdopen(1,\"w\");" << std::endl << " }" << std::endl << " if (fp->fd == 0)" << std::endl << " {" << std::endl << " free(fp);" << std::endl << " return 0;" << std::endl << " }" << std::endl << " fp->iomode = HDDM_STREAM_OUTPUT;" << std::endl << " len = strlen(HDDM_" << classPrefix << "_DocumentString);" << std::endl << " head = (char*)malloc(len+1);" << std::endl << " strcpy(head,HDDM_" << classPrefix << "_DocumentString);" << std::endl << " if (fwrite(head,1,len,fp->fd) != len)" << std::endl << " {" << std::endl << " fprintf(stderr,\"HDDM Error: \");" << std::endl << " fprintf(stderr,\"error writing to \");" << std::endl << " fprintf(stderr,\"output file %s\\n\",filename);" << std::endl << " exit(9);" << std::endl << " }" << std::endl << " fp->filename = " << "(char*)malloc(strlen(filename) + 1);" << std::endl << " strcpy(fp->filename,filename);" << std::endl << " fp->popTop = 0;" << std::endl << " fp->xdrs = (XDR*)malloc(sizeof(XDR));" << std::endl << " xdrstdio_create(fp->xdrs,fp->fd,XDR_ENCODE);" << std::endl << " free(head);" << std::endl << " return fp;" << std::endl << "}" << std::endl; } /* Generate the code to close an open hddm file */ void CodeBuilder::constructCloseFunc(DOMElement* el) { XtString tagS(el->getTagName()); XtString tagType = tagS.simpleType(); XtString tagT(tagType); tagT.erase(tagT.rfind('_')); cFile << std::endl << "void popaway(popNode* p)" << std::endl << "{" << std::endl << " if (p)" << std::endl << " {" << std::endl << " int n;" << std::endl << " for (n = 0; n < p->popListLength; n++)" << std::endl << " {" << std::endl << " popaway(p->popList[n]);" << std::endl << " }" << std::endl << " free(p);" << std::endl << " }" << std::endl << "}" << std::endl << std::endl << "void close_" << tagT << "(" << classPrefix << "_iostream_t* fp)" << std::endl << "{" << std::endl << " xdr_destroy(fp->xdrs);" << std::endl << " free(fp->xdrs);" << std::endl << " fclose(fp->fd);" << std::endl << " free(fp->filename);" << std::endl << " popaway(fp->popTop);" << std::endl << " free(fp);" << std::endl << "}" << std::endl; } #endif /* Generate the xml template in normal form and store in a string */ void CodeBuilder::constructDocument(DOMElement* el) { static int indent = 0; cFile << "\""; for (int n = 0; n < indent; n++) { cFile << " "; } XtString tagS(el->getTagName()); cFile << "<" << tagS; DOMNamedNodeMap* attrList = el->getAttributes(); int attrListLength = attrList->getLength(); for (int a = 0; a < attrListLength; a++) { DOMNode* node = attrList->item(a); XtString nameS(node->getNodeName()); XtString valueS(node->getNodeValue()); cFile << " " << nameS << "=\\\"" << valueS << "\\\""; } DOMNodeList* contList = el->getChildNodes(); int contListLength = contList->getLength(); if (contListLength > 0) { cFile << ">\\n\"" << std::endl; indent++; for (int c = 0; c < contListLength; c++) { DOMNode* node = contList->item(c); if (node->getNodeType() == DOMNode::ELEMENT_NODE) { DOMElement* contEl = (DOMElement*) node; constructDocument(contEl); } } indent--; cFile << "\""; for (int n = 0; n < indent; n++) { cFile << " "; } cFile << "\\n\"" << std::endl; } else { cFile << " />\\n\"" << std::endl; } }