1 /**
2  * @file    SBase.cpp
3  * @brief   Implementation of SBase, the base object of all SBML objects.
4  * @author  Ben Bornstein
5  *
6  * <!--------------------------------------------------------------------------
7  * This file is part of libSBML.  Please visit http://sbml.org for more
8  * information about SBML, and the latest version of libSBML.
9  *
10  * Copyright (C) 2020 jointly by the following organizations:
11  *     1. California Institute of Technology, Pasadena, CA, USA
12  *     2. University of Heidelberg, Heidelberg, Germany
13  *     3. University College London, London, UK
14  *
15  * Copyright (C) 2019 jointly by the following organizations:
16  *     1. California Institute of Technology, Pasadena, CA, USA
17  *     2. University of Heidelberg, Heidelberg, Germany
18  *
19  * Copyright (C) 2013-2018 jointly by the following organizations:
20  *     1. California Institute of Technology, Pasadena, CA, USA
21  *     2. EMBL European Bioinformatics Institute (EMBL-EBI), Hinxton, UK
22  *     3. University of Heidelberg, Heidelberg, Germany
23  *
24  * Copyright (C) 2009-2013 jointly by the following organizations:
25  *     1. California Institute of Technology, Pasadena, CA, USA
26  *     2. EMBL European Bioinformatics Institute (EMBL-EBI), Hinxton, UK
27  *
28  * Copyright (C) 2006-2008 by the California Institute of Technology,
29  *     Pasadena, CA, USA
30  *
31  * Copyright (C) 2002-2005 jointly by the following organizations:
32  *     1. California Institute of Technology, Pasadena, CA, USA
33  *     2. Japan Science and Technology Agency, Japan
34  *
35  * This library is free software; you can redistribute it and/or modify it
36  * under the terms of the GNU Lesser General Public License as published by
37  * the Free Software Foundation.  A copy of the license agreement is provided
38  * in the file named "LICENSE.txt" included with this software distribution
39  * and also available online as http://sbml.org/software/libsbml/license.html
40  * ---------------------------------------------------------------------- -->*/
41 
42 #include <sstream>
43 
44 #include <sbml/xml/XMLError.h>
45 #include <sbml/xml/XMLErrorLog.h>
46 #include <sbml/xml/XMLOutputStream.h>
47 #include <sbml/xml/XMLInputStream.h>
48 #include <sbml/xml/XMLToken.h>
49 #include <sbml/xml/XMLNode.h>
50 
51 #include <sbml/util/util.h>
52 
53 #include <sbml/annotation/RDFAnnotation.h>
54 
55 #include <sbml/KineticLaw.h>
56 #include <sbml/SBMLError.h>
57 #include <sbml/SBMLErrorLog.h>
58 #include <sbml/SBMLDocument.h>
59 #include <sbml/Model.h>
60 #include <sbml/ListOf.h>
61 #include <sbml/SBase.h>
62 
63 #include <sbml/util/IdList.h>
64 #include <sbml/util/IdentifierTransformer.h>
65 #include <sbml/extension/SBasePlugin.h>
66 #include <sbml/extension/ISBMLExtensionNamespaces.h>
67 #include <sbml/extension/SBMLExtensionRegistry.h>
68 #include <sbml/extension/SBMLExtensionException.h>
69 #include <sbml/util/CallbackRegistry.h>
70 
71 /** @cond doxygenIgnored */
72 using namespace std;
73 /** @endcond */
74 
75 LIBSBML_CPP_NAMESPACE_BEGIN
76 
77 #ifdef __cplusplus
78 
79 /** @cond doxygenLibsbmlInternal */
80 /*
81  * Used by the Destructor to delete each item in mPlugins.
82  */
83 struct DeletePluginEntity : public unary_function<SBasePlugin*, void>
84 {
operator ()DeletePluginEntity85   void operator() (SBasePlugin* sb) { delete sb; }
86 };
87 
88 
89 /*
90  * Used by the Copy Constructor to clone each item in mPlugins.
91  */
92 struct ClonePluginEntity : public unary_function<SBasePlugin*, SBasePlugin*>
93 {
operator ()ClonePluginEntity94   SBasePlugin* operator() (SBasePlugin* sb) {
95     if (!sb) return NULL;
96     return sb->clone();
97   }
98 };
99 /** @endcond */
100 
101 
102 SBase*
getElementBySId(const std::string & id)103 SBase::getElementBySId(const std::string& id)
104 {
105   if (id.empty()) return NULL;
106   return getElementFromPluginsBySId(id);
107 }
108 
109 const SBase*
getElementBySId(const std::string & id) const110 SBase::getElementBySId(const std::string& id) const
111 {
112   SBase* thus = const_cast<SBase*>(this);
113   return thus->getElementBySId(id);
114 }
115 
116 
117 SBase*
getElementByMetaId(const std::string & metaid)118 SBase::getElementByMetaId(const std::string& metaid)
119 {
120   if (metaid.empty()) return NULL;
121   return getElementFromPluginsByMetaId(metaid);
122 }
123 
124 const SBase*
getElementByMetaId(const std::string & metaid) const125 SBase::getElementByMetaId(const std::string& metaid) const
126 {
127   SBase* thus = const_cast<SBase*>(this);
128   return thus->getElementByMetaId(metaid);
129 }
130 
131 List*
getAllElements(ElementFilter * filter)132 SBase::getAllElements(ElementFilter *filter)
133 {
134   return getAllElementsFromPlugins(filter);
135 }
136 
137 void
renameSIdRefs(const std::string & oldid,const std::string & newid)138 SBase::renameSIdRefs(const std::string& oldid, const std::string& newid)
139 {
140   //No SIdRefs in SBase, but plugins might have some.
141   for (unsigned int p = 0; p < getNumPlugins(); p++)
142   {
143     getPlugin(p)->renameSIdRefs(oldid, newid);
144   }
145 }
146 
147 void
renameMetaIdRefs(const std::string & oldid,const std::string & newid)148 SBase::renameMetaIdRefs(const std::string& oldid, const std::string& newid)
149 {
150   //The only thing in core that uses metaids is the annotation element.  If the metaid of an SBase object is changed, and the annotation was in the 'sbml-official' form, the rdf:about will be changed automatically, so this function doesn't need to do anything.  However, we do need the function itself so that packages can extend it for their own purposes (such as comp, with its 'metaIdRef' attributes, and annot, which one would imagine would use something similar).
151 
152   //The following code is here in case you want a hacky solution for your own package:
153   /*
154   if (oldid == newid) return;
155   if (isSetAnnotation()) {
156     string oldrdfabout = "rdf:about=\"#" + oldid;
157     string newrdfabout = "rdf:about=\"#" + newid;
158     string annot = getAnnotationString();
159     size_t place = annot.find(oldrdfabout);
160     while (place != string::npos) {
161       annot.replace(place, oldrdfabout.size(), newrdfabout);
162       place = annot.find(oldrdfabout);
163     }
164   }
165   */
166   //We also need to check the plugins:
167   for (unsigned int p = 0; p < getNumPlugins(); p++)
168   {
169     getPlugin(p)->renameMetaIdRefs(oldid, newid);
170   }
171 }
172 
173 void
renameUnitSIdRefs(const std::string & oldid,const std::string & newid)174 SBase::renameUnitSIdRefs(const std::string& oldid, const std::string& newid)
175 {
176   //No UnitSIdRefs in SBase, either.  But check the plugins.
177   for (unsigned int p = 0; p < getNumPlugins(); p++)
178   {
179     getPlugin(p)->renameUnitSIdRefs(oldid, newid);
180   }
181 }
182 
183 /** @cond doxygenLibsbmlInternal */
184 SBase*
getElementFromPluginsBySId(std::string id)185 SBase::getElementFromPluginsBySId(std::string id)
186 {
187   for (size_t i=0; i < mPlugins.size(); i++)
188   {
189     SBase* subObj = mPlugins[i]->getElementBySId(id);
190     if (subObj != NULL) return subObj;
191   }
192   return NULL;
193 }
194 /** @endcond */
195 
196 
197 /** @cond doxygenLibsbmlInternal */
198 SBase*
getElementFromPluginsByMetaId(std::string metaid)199 SBase::getElementFromPluginsByMetaId(std::string metaid)
200 {
201   for (size_t i=0; i < mPlugins.size(); i++)
202   {
203     SBase* subObj = mPlugins[i]->getElementByMetaId(metaid);
204     if (subObj != NULL) return subObj;
205   }
206   return NULL;
207 }
208 /** @endcond */
209 
210 
211 /** @cond doxygenLibsbmlInternal */
hasNonstandardIdentifierBeginningWith(const std::string &)212 bool SBase::hasNonstandardIdentifierBeginningWith(const std::string&)
213 {
214   return false;
215 }
216 /** @endcond */
217 
218 
219 /** @cond doxygenLibsbmlInternal */
220 int
prependStringToAllIdentifiers(const std::string & prefix)221 SBase::prependStringToAllIdentifiers(const std::string& prefix)
222 {
223   int ret;
224 
225   if (isSetMetaId())
226   {
227     ret = setMetaId(prefix + getMetaId());
228     if (ret != LIBSBML_OPERATION_SUCCESS)
229     {
230       return ret;
231     }
232   }
233 
234   for (unsigned int p = 0; p < getNumPlugins(); p++)
235   {
236     ret = getPlugin(p)->prependStringToAllIdentifiers(prefix);
237     if (ret != LIBSBML_OPERATION_SUCCESS)
238     {
239       return ret;
240     }
241   }
242 
243 
244   // Must use 'IdAttribute' functions since some elements like rules
245   // return a different value for 'Id' functions alone.
246 
247   if (isSetIdAttribute())
248   {
249     ret = setIdAttribute(prefix + getIdAttribute());
250     if (ret != LIBSBML_OPERATION_SUCCESS)
251     {
252       return ret;
253     }
254   }
255 
256   return LIBSBML_OPERATION_SUCCESS;
257 }
258   /** @endcond */
259 
260 
261 /** @cond doxygenLibsbmlInternal */
262 int
transformIdentifiers(IdentifierTransformer * idTransformer)263 SBase::transformIdentifiers(IdentifierTransformer* idTransformer)
264 {
265   int ret = LIBSBML_OPERATION_SUCCESS;
266 
267   // call plugins
268   for (unsigned int p = 0; p < getNumPlugins(); ++p)
269   {
270     ret = getPlugin(p)->transformIdentifiers(idTransformer);
271     if (ret != LIBSBML_OPERATION_SUCCESS)
272     {
273       return ret;
274     }
275   }
276 
277   // call transformer
278   if (idTransformer != NULL)
279   {
280     ret = idTransformer->transform(this);
281     if (ret != LIBSBML_OPERATION_SUCCESS)
282     {
283       return ret;
284     }
285   }
286 
287   return ret;
288 }
289 /** @endcond */
290 
291 List*
getAllElementsFromPlugins(ElementFilter * filter)292 SBase::getAllElementsFromPlugins(ElementFilter *filter)
293 {
294   List* ret = new List();
295   for (size_t i=0; i < mPlugins.size(); i++)
296   {
297     List* sublist = mPlugins[i]->getAllElements(filter);
298     if (sublist != NULL)
299     {
300       if (sublist->getSize() > 0)
301         ret->transferFrom(sublist);
302       delete sublist;
303     }
304   }
305   return ret;
306 }
307 
308 
309 /** @cond doxygenLibsbmlInternal */
310 /*
311  * Creates a new SBase object with the given level and version.
312  * Only subclasses may create SBase objects.
313  */
SBase(unsigned int level,unsigned int version)314 SBase::SBase (unsigned int level, unsigned int version) :
315    mId   ( "" )
316  , mName ( "" )
317  , mMetaId ( "" )
318  , mNotes     ( NULL )
319  , mAnnotation( NULL )
320  , mSBML      ( NULL )
321  , mSBMLNamespaces (NULL)
322  , mUserData(NULL)
323  , mSBOTerm   ( -1 )
324  , mLine      ( 0 )
325  , mColumn    ( 0 )
326  , mParentSBMLObject (NULL)
327  , mCVTerms   ( NULL )
328  , mHistory   ( NULL )
329  , mHasBeenDeleted (false)
330  , mEmptyString ("")
331  , mURI("")
332  , mHistoryChanged (false)
333  , mCVTermsChanged (false)
334  , mAttributesOfUnknownPkg()
335  , mAttributesOfUnknownDisabledPkg()
336  , mElementsOfUnknownPkg()
337  , mElementsOfUnknownDisabledPkg()
338 {
339   mSBMLNamespaces = new SBMLNamespaces(level, version);
340 
341   //
342   // Sets the XMLNS URI of corresponding SBML Level/Version to
343   // the element namespace (mURI) of this object.
344   //
345   // (NOTES) Package developers must (1) override the mSBMLNamespaces of this
346   //         object with the corresponding SBMLExtensionNamespaces (template)
347   //         class in their packages and (2) override the element namespace (mURI)
348   //         of this object with the corresponding package's URI in the constructor
349   //         of SBase derived class in thier packages.
350   //
351   setElementNamespace(mSBMLNamespaces->getURI());
352 }
353 
354 
355 
356 /*
357  * Creates a new SBase object with the given SBMLNamespaces.
358  * Only subclasses may create SBase objects.
359  */
SBase(SBMLNamespaces * sbmlns)360 SBase::SBase (SBMLNamespaces *sbmlns) :
361    mId   ( "" )
362  , mName ( "" )
363  , mMetaId ( "" )
364  , mNotes     ( NULL )
365  , mAnnotation( NULL )
366  , mSBML      ( NULL )
367  , mSBMLNamespaces (NULL)
368  , mUserData(NULL)
369  , mSBOTerm   ( -1 )
370  , mLine      ( 0 )
371  , mColumn    ( 0 )
372  , mParentSBMLObject (NULL)
373  , mCVTerms   ( NULL )
374  , mHistory   ( NULL )
375  , mHasBeenDeleted (false)
376  , mEmptyString ("")
377  , mURI("")
378  , mHistoryChanged (false)
379  , mCVTermsChanged (false)
380  , mAttributesOfUnknownPkg()
381  , mAttributesOfUnknownDisabledPkg()
382  , mElementsOfUnknownPkg()
383  , mElementsOfUnknownDisabledPkg()
384 {
385   if (!sbmlns)
386   {
387     std::string err("SBase::SBase(SBMLNamespaces*, SBaseExtensionPoint*) : SBMLNamespaces is null");
388     throw SBMLConstructorException(err);
389   }
390   mSBMLNamespaces = sbmlns->clone();
391 
392   //
393   // Sets the XMLNS URI of corresponding SBML Level/Version to
394   // the element namespace (mURI) of this object.
395   //
396   // (NOTES) Package developers must override the element namespace (mURI)
397   //         of this object with the corresponding package's URI in the constructor
398   //         of SBase derived class in thier packages.
399   //
400 
401 #if 0
402     cout << "[DEBUG] SBase::SBase(SBMLNamespaces*,...) " << static_cast<SBMLNamespaces>(*mSBMLNamespaces).getURI() << endl;
403 #endif
404 
405   setElementNamespace(static_cast<SBMLNamespaces>(*mSBMLNamespaces).getURI());
406 }
407 /** @endcond */
408 
409 
410 /** @cond doxygenLibsbmlInternal */
411 /*
412  * Copy constructor. Creates a copy of this SBase object.
413  */
SBase(const SBase & orig)414 SBase::SBase(const SBase& orig)
415   : mId (orig.mId)
416   , mName (orig.mName)
417   , mMetaId (orig.mMetaId)
418   , mNotes (NULL)
419   , mAnnotation (NULL)
420   , mSBML (NULL)
421   , mSBMLNamespaces(NULL)
422   , mUserData(orig.mUserData)
423   , mSBOTerm(orig.mSBOTerm)
424   , mLine(orig.mLine)
425   , mColumn(orig.mColumn)
426   , mParentSBMLObject(NULL)
427   , mCVTerms(NULL)
428   , mHistory(NULL)
429   , mHasBeenDeleted(false)
430   , mEmptyString()
431   , mPlugins(orig.mPlugins.size())
432   , mDisabledPlugins()
433   , mURI(orig.mURI)
434   , mHistoryChanged(orig.mHistoryChanged)
435   , mCVTermsChanged(orig.mCVTermsChanged)
436   , mAttributesOfUnknownPkg (orig.mAttributesOfUnknownPkg)
437   , mAttributesOfUnknownDisabledPkg (orig.mAttributesOfUnknownDisabledPkg)
438   , mElementsOfUnknownPkg (orig.mElementsOfUnknownPkg)
439   , mElementsOfUnknownDisabledPkg (orig.mElementsOfUnknownDisabledPkg)
440 {
441   if(orig.mNotes != NULL)
442     this->mNotes = new XMLNode(*const_cast<SBase&>(orig).getNotes());
443 
444   if(orig.mAnnotation != NULL)
445     this->mAnnotation = new XMLNode(*const_cast<SBase&>(orig).mAnnotation);
446 
447   if(orig.getSBMLNamespaces() != NULL)
448     this->mSBMLNamespaces =
449     new SBMLNamespaces(*const_cast<SBase&>(orig).getSBMLNamespaces());
450 
451   if(orig.mCVTerms != NULL)
452   {
453     this->mCVTerms  = new List();
454     unsigned int i,iMax = orig.mCVTerms->getSize();
455     for(i = 0; i < iMax; ++i)
456     {
457       this->mCVTerms
458         ->add(static_cast<CVTerm*>(orig.mCVTerms->get(i))->clone());
459     }
460   }
461 
462   if (orig.mHistory != NULL)
463   {
464     this->mHistory = orig.mHistory->clone();
465   }
466 
467   transform( orig.mPlugins.begin(), orig.mPlugins.end(),
468              mPlugins.begin(), ClonePluginEntity() );
469   for (size_t i=0; i < mPlugins.size(); ++i)
470   {
471     mPlugins[i]->connectToParent(this);
472   }
473 
474 }
475 /** @endcond */
476 
477 
478 /*
479  * Destroy this SBase object.
480  */
~SBase()481 SBase::~SBase ()
482 {
483   if (mNotes != NULL)       delete mNotes;
484   if (mAnnotation != NULL)  delete mAnnotation;
485   if (mSBMLNamespaces != NULL)  delete mSBMLNamespaces;
486   if (mCVTerms != NULL)
487   {
488     unsigned int size = mCVTerms->getSize();
489     while (size > 0)
490     {
491       delete static_cast<CVTerm*>( mCVTerms->remove(0) );
492       size--;
493     }
494     delete mCVTerms;
495   }
496   if (mHistory != NULL) delete mHistory;
497   mHasBeenDeleted = true;
498 
499   for_each( mPlugins.begin(), mPlugins.end(), DeletePluginEntity() );
500   deleteDisabledPlugins(false);
501 }
502 
503 /*
504  * Assignment operator
505  */
operator =(const SBase & rhs)506 SBase& SBase::operator=(const SBase& rhs)
507 {
508   if(&rhs!=this)
509   {
510     this->mId     = rhs.mId;
511     this->mName   = rhs.mName;
512     this->mMetaId = rhs.mMetaId;
513 
514     delete this->mNotes;
515 
516     if(rhs.mNotes != NULL)
517       this->mNotes = new XMLNode(*const_cast<SBase&>(rhs).getNotes());
518     else
519       this->mNotes = NULL;
520 
521     delete this->mAnnotation;
522 
523     if(rhs.mAnnotation != NULL)
524       this->mAnnotation = new XMLNode(*const_cast<SBase&>(rhs).mAnnotation);
525     else
526       this->mAnnotation = NULL;
527 
528     this->mSBML       = rhs.mSBML;
529     this->mSBOTerm    = rhs.mSBOTerm;
530     this->mLine       = rhs.mLine;
531     this->mColumn     = rhs.mColumn;
532     this->mParentSBMLObject = rhs.mParentSBMLObject;
533     this->mUserData   = rhs.mUserData;
534     this->mAttributesOfUnknownPkg = rhs.mAttributesOfUnknownPkg;
535     this->mAttributesOfUnknownDisabledPkg = rhs.mAttributesOfUnknownDisabledPkg;
536     this->mElementsOfUnknownPkg = rhs.mElementsOfUnknownPkg;
537     this->mElementsOfUnknownDisabledPkg = rhs.mElementsOfUnknownDisabledPkg;
538 
539     delete this->mSBMLNamespaces;
540 
541     if(rhs.mSBMLNamespaces != NULL)
542       this->mSBMLNamespaces =
543       new SBMLNamespaces(*const_cast<SBase&>(rhs).mSBMLNamespaces);
544     else
545       this->mSBMLNamespaces = NULL;
546 
547 
548     if(this->mCVTerms != NULL)
549     {
550       unsigned int size = this->mCVTerms->getSize();
551       while (size--) delete static_cast<CVTerm*>( this->mCVTerms->remove(0) );
552       delete this->mCVTerms;
553     }
554 
555     if(rhs.mCVTerms != NULL)
556     {
557       this->mCVTerms  = new List();
558       unsigned int i,iMax = rhs.mCVTerms->getSize();
559       for(i = 0; i < iMax; ++i)
560       {
561         this->mCVTerms
562           ->add(static_cast<CVTerm*>(rhs.mCVTerms->get(i))->clone());
563       }
564     }
565     else
566     {
567       this->mCVTerms = NULL;
568     }
569 
570     delete this->mHistory;
571     if (rhs.mHistory != NULL)
572     {
573       this->mHistory = rhs.mHistory->clone();
574     }
575     else
576     {
577       this->mHistory = NULL;
578     }
579 
580     this->mHasBeenDeleted = rhs.mHasBeenDeleted;
581     this->mURI = rhs.mURI;
582     this->mHistoryChanged = rhs.mHistoryChanged;
583     this->mCVTermsChanged = rhs.mCVTermsChanged;
584 
585     for_each( mPlugins.begin(), mPlugins.end(), DeletePluginEntity() );
586     mPlugins.resize( rhs.mPlugins.size() );
587     transform( rhs.mPlugins.begin(), rhs.mPlugins.end(),
588                mPlugins.begin(), ClonePluginEntity() );
589   }
590 
591   return *this;
592 }
593 
594 
595 /** @cond doxygenLibsbmlInternal */
596 /*
597  * Loads SBasePlugin derived objects corresponding to the URIs contained
598  * in the given SBMLNamespaces (if any) for package extension.
599  */
600 void
loadPlugins(SBMLNamespaces * sbmlns)601 SBase::loadPlugins(SBMLNamespaces *sbmlns)
602 {
603   if (!sbmlns) return;
604 
605   //
606   // (EXTENSION)
607   //
608   XMLNamespaces *xmlns = sbmlns->getNamespaces();
609 
610   if (xmlns)
611   {
612     int numxmlns= xmlns->getLength();
613     SBaseExtensionPoint extPoint(getPackageName(), getTypeCode(), getElementName());
614     SBaseExtensionPoint genericPoint("all", SBML_GENERIC_SBASE);
615 
616     for (int i=0; i < numxmlns; i++)
617     {
618       const std::string &uri = xmlns->getURI(i);
619       const SBMLExtension* sbmlext = SBMLExtensionRegistry::getInstance().getExtensionInternal(uri);
620 
621       if (sbmlext && sbmlext->isEnabled())
622       {
623 #if 0
624           cout << "[DEBUG] SBase::loadPlugins() " << uri
625                << " is registered in "
626                << SBMLTypeCode_toString(getTypeCode(), getPackageName().c_str())
627                << endl;
628 #endif
629         const std::string &prefix = xmlns->getPrefix(i);
630         const SBasePluginCreatorBase* sbPluginCreator = sbmlext->getSBasePluginCreator(extPoint);
631 
632         if (sbPluginCreator == NULL)
633         {
634           sbPluginCreator = sbmlext->getSBasePluginCreator(genericPoint);
635         }
636 
637         if (sbPluginCreator)
638         {
639           // (debug)
640           //cout << "sbPluginCreator " << sbPluginCreator << endl;
641           //sbPluginCreator->createPlugin(uri,prefix);
642           // (debug)
643           SBasePlugin* entity = sbPluginCreator->createPlugin(uri,prefix,xmlns);
644           entity->connectToParent(this);
645           mPlugins.push_back(entity);
646         }
647 #if 0
648         else
649         {
650             cout << "[DEBUG] SBase::loadPlugins() " << uri
651                  << " is not registered in "
652                  << SBMLTypeCode_toString(getTypeCode(), getPackageName().c_str())
653                  << endl;
654         }
655 #endif
656       }
657       else
658       {
659   //
660   // (NOTE)
661         //
662   // SBMLExtensionException should be thrown if the corresponding package
663         // extension is not loaded.
664         // However, currently, no idea how to check if the uri belongs to extension
665         // package or not (e.g. XHTML namespace or other namespace can be given).
666   //
667 #if 0
668         std::ostringstream errMsg;
669 
670         if (sbmlext)
671         {
672           errMsg << "Package \"" << sbmlext->getName() << "\" (" << uri << ") for \"<"
673                  << SBMLTypeCode_toString(getTypeCode(), getPackageName().c_str())
674                  << ">\" element is disabled.";
675   }
676   else
677         {
678           errMsg << "Package \"" << uri << "\" for \"<"
679                  << SBMLTypeCode_toString(getTypeCode(), getPackageName().c_str())
680                  << ">\" element is not supported.";
681         }
682 
683         throw SBMLExtensionException(errMsg.str());
684 #endif
685       }
686     }
687   }
688 }
689 /** @endcond */
690 
691 
692 /*
693  * @return the metaid of this SBML object.
694  */
695 const string&
getMetaId() const696 SBase::getMetaId () const
697 {
698   return mMetaId;
699 }
700 
701 
702 /*
703  * @return the metaid of this SBML object.
704  */
705 string&
getMetaId()706 SBase::getMetaId ()
707 {
708   return mMetaId;
709 }
710 
711 
712 /*
713  * @return the id of this SBML object.
714  */
715 const string&
getId() const716 SBase::getId () const
717 {
718   if (getLevel() == 3 && getVersion() > 1)
719   {
720     return mId;
721   }
722   else
723   {
724     return mEmptyString;
725   }
726 }
727 
728 
729 
730 /*
731  * @return the name of this SBML object.
732  */
733 const string&
getName() const734 SBase::getName () const
735 {
736   if (getLevel() == 3 && getVersion() > 1)
737   {
738     return mName;
739   }
740   else
741   {
742     return mEmptyString;
743   }
744 }
745 
746 const string&
getIdAttribute() const747 SBase::getIdAttribute () const
748 {
749   return mId;
750 }
751 
752 
753 /*
754  * @return the notes of this SBML object.
755  */
756 XMLNode*
getNotes()757 SBase::getNotes()
758 {
759   return mNotes;
760 }
761 
762 
763 XMLNode*
getNotes() const764 SBase::getNotes() const
765 {
766   return mNotes;
767 }
768 
769 
770 /*
771  * @return the notes of this SBML object by string.
772  */
773 std::string
getNotesString()774 SBase::getNotesString()
775 {
776   return XMLNode::convertXMLNodeToString(mNotes);
777 }
778 
779 
780 std::string
getNotesString() const781 SBase::getNotesString() const
782 {
783   return XMLNode::convertXMLNodeToString(mNotes);
784 }
785 
786 
787 /*
788  * @return the annotation of this SBML object.
789  */
790 XMLNode*
getAnnotation()791 SBase::getAnnotation ()
792 {
793   syncAnnotation();
794 
795   return mAnnotation;
796 }
797 
798 
799 XMLNode*
getAnnotation() const800 SBase::getAnnotation () const
801 {
802   return const_cast<SBase *>(this)->getAnnotation();
803 }
804 
805 
806 /*
807  * @return the annotation of this SBML object by string.
808  */
809 std::string
getAnnotationString()810 SBase::getAnnotationString ()
811 {
812   return XMLNode::convertXMLNodeToString(getAnnotation());
813 }
814 
815 
816 std::string
getAnnotationString() const817 SBase::getAnnotationString () const
818 {
819   return XMLNode::convertXMLNodeToString(getAnnotation());
820 }
821 
822 
823 /** @cond doxygenLibsbmlInternal */
824 std::string
getURI() const825 SBase::getURI() const
826 {
827   const string &package = getPackageName();
828   const SBMLDocument* doc = getSBMLDocument();
829 
830   if (doc == NULL)
831     return getElementNamespace();
832 
833   SBMLNamespaces* sbmlns = doc->getSBMLNamespaces();
834 
835   if (sbmlns == NULL)
836     return getElementNamespace();
837 
838   if (package == "" || package == "core")
839     return getElementNamespace();
840 
841   string packageURI = sbmlns->getNamespaces()->getURI(package);
842   if (!packageURI.empty())
843     return packageURI;
844 
845   return getElementNamespace();
846 }
847 /** @endcond */
848 
849 
850 /** @cond doxygenLibsbmlInternal */
851 /*
852  * This function does nothing itself--subclasses with ASTNode subelements must override this function.
853  */
854 void
replaceSIDWithFunction(const std::string &,const ASTNode *)855 SBase::replaceSIDWithFunction(const std::string&, const ASTNode*)
856 {
857 }
858 /** @endcond */
859 
860 /** @cond doxygenLibsbmlInternal */
861 /*
862  * This function does nothing itself--subclasses with ASTNode subelements must override this function.
863  */
864 void
divideAssignmentsToSIdByFunction(const std::string &,const ASTNode *)865 SBase::divideAssignmentsToSIdByFunction(const std::string&, const ASTNode*)
866 {
867 }
868 /** @endcond */
869 
870 /** @cond doxygenLibsbmlInternal */
871 void
multiplyAssignmentsToSIdByFunction(const std::string &,const ASTNode *)872 SBase::multiplyAssignmentsToSIdByFunction(const std::string&, const ASTNode*)
873 {
874 }
875 /** @endcond */
876 
877 void *
getUserData() const878 SBase::getUserData() const
879 {
880   return this->mUserData;
881 }
882 
883 
884 int
setUserData(void * userData)885 SBase::setUserData(void *userData)
886 {
887   this->mUserData = userData;
888   if (userData == NULL && mUserData == NULL)
889   {
890     return LIBSBML_OPERATION_SUCCESS;
891   }
892   else if (mUserData != NULL)
893   {
894     return LIBSBML_OPERATION_SUCCESS;
895   }
896   else
897   {
898     return LIBSBML_OPERATION_FAILED;
899   }
900 }
901 
902 bool
isSetUserData() const903 SBase::isSetUserData() const
904 {
905   if (mUserData != NULL)
906   {
907     return true;
908   }
909   else
910   {
911     return false;
912   }
913 }
914 
915 int
unsetUserData()916 SBase::unsetUserData()
917 {
918   this->mUserData = NULL;
919   if (mUserData == NULL)
920   {
921     return LIBSBML_OPERATION_SUCCESS;
922   }
923   else
924   {
925     return LIBSBML_OPERATION_FAILED;
926   }
927 }
928 
929 /*
930  * @return the Namespaces associated with this SBML object
931  */
932 XMLNamespaces*
getNamespaces() const933 SBase::getNamespaces() const
934 {
935   if (mSBML != NULL)
936     return mSBML->getSBMLNamespaces()->getNamespaces();
937   if (mSBMLNamespaces != NULL)
938     return mSBMLNamespaces->getNamespaces();
939   return NULL;
940 }
941 
942 
943 /*
944  * @return the parent SBMLDocument of this SBML object.
945  */
946 const SBMLDocument*
getSBMLDocument() const947 SBase::getSBMLDocument () const
948 {
949   if (mSBML != NULL)
950   {
951     // if the doc object has been deleted the pointer is
952     // still valid but points to nothing
953     try
954     {
955       if (mSBML->getHasBeenDeleted())
956       {
957         return NULL;
958       }
959       else
960       {
961         return mSBML;
962       }
963     }
964     catch ( ... )
965     {
966       return NULL;
967     }
968   }
969 
970   return mSBML;
971 }
972 
973 /*
974  * @return the parent SBMLDocument of this SBML object.
975  */
976 SBMLDocument*
getSBMLDocument()977 SBase::getSBMLDocument ()
978 {
979   if (mSBML != NULL)
980   {
981     // if the doc object has been deleted the pointer is
982     // still valid but points to nothing
983     try
984     {
985       if (mSBML->getHasBeenDeleted())
986       {
987         return NULL;
988       }
989       else
990       {
991         return mSBML;
992       }
993     }
994     catch ( ... )
995     {
996       return NULL;
997     }
998   }
999   return mSBML;
1000 }
1001 SBase*
getParentSBMLObject()1002 SBase::getParentSBMLObject ()
1003 {
1004   if (mParentSBMLObject != NULL)
1005   {
1006     // if the parent object has been deleted the pointer is
1007     // still valid but points to nothing
1008     try
1009     {
1010       if (mParentSBMLObject->getHasBeenDeleted())
1011       {
1012         return NULL;
1013       }
1014       else
1015       {
1016         return mParentSBMLObject;
1017       }
1018     }
1019     catch ( ... )
1020     {
1021       return NULL;
1022     }
1023   }
1024 
1025   return mParentSBMLObject;
1026 }
1027 
1028 const SBase*
getParentSBMLObject() const1029 SBase::getParentSBMLObject () const
1030 {
1031   if (mParentSBMLObject != NULL)
1032   {
1033     // if the parent object has been deleted the pointer is
1034     // still valid but points to nothing
1035     try
1036     {
1037       if (mParentSBMLObject->getHasBeenDeleted())
1038       {
1039         return NULL;
1040       }
1041       else
1042       {
1043         return mParentSBMLObject;
1044       }
1045     }
1046     catch ( ... )
1047     {
1048       return NULL;
1049     }
1050   }
1051 
1052   return mParentSBMLObject;
1053 }
1054 
1055 /*
1056  * @return the sboTerm as an integer.  If not set,
1057  * sboTerm will be -1.
1058  */
1059 int
getSBOTerm() const1060 SBase::getSBOTerm () const
1061 {
1062   return mSBOTerm;
1063 }
1064 
1065 
1066 /*
1067  * @return the sboTerm as a string.  If not set,
1068  * return an empty string.
1069  */
1070 std::string
getSBOTermID() const1071 SBase::getSBOTermID () const
1072 {
1073   return SBO::intToString(mSBOTerm);
1074 }
1075 
1076 
1077 /*
1078  * @return the sboTerm as a identoifoers.org url.  If not set,
1079  * return an empty string.
1080  */
1081 std::string
getSBOTermAsURL() const1082 SBase::getSBOTermAsURL () const
1083 {
1084   std::string result = "";
1085 
1086   if ( SBO::checkTerm(mSBOTerm) )
1087   {
1088     ostringstream stream;
1089     stream << "http://identifiers.org/biomodels.sbo/SBO:";
1090     stream << setw(7) << setfill('0') << mSBOTerm;
1091     result = stream.str();
1092   }
1093 
1094   return result;
1095 }
1096 
1097 
1098 /*
1099  * @return the line number of this SBML object.
1100  */
1101 unsigned int
getLine() const1102 SBase::getLine () const
1103 {
1104   return mLine;
1105 }
1106 
1107 
1108 /*
1109  * @return the column number of this SBML object.
1110  */
1111 unsigned int
getColumn() const1112 SBase::getColumn () const
1113 {
1114   return mColumn;
1115 }
1116 
1117 
1118 ModelHistory*
getModelHistory() const1119 SBase::getModelHistory() const
1120 {
1121   return mHistory;
1122 }
1123 
1124 ModelHistory*
getModelHistory()1125 SBase::getModelHistory()
1126 {
1127   return mHistory;
1128 }
1129 
1130 
1131 /*
1132  * @return @c true if the metaid of this SBML object is set, false
1133  * otherwise.
1134  */
1135 bool
isSetMetaId() const1136 SBase::isSetMetaId () const
1137 {
1138   return (mMetaId.empty() == false);
1139 }
1140 
1141 
1142 /*
1143  * NOTE: THIS IS FOR BACKWARD COMPATABILITY REASONS
1144  *
1145  * @return @c true if the id of this SBML object is set, false
1146  * otherwise.
1147  */
1148 bool
isSetId() const1149 SBase::isSetId () const
1150 {
1151   return (getId().empty() == false);
1152 }
1153 
1154 
1155 /*
1156  * NOTE: THIS IS FOR BACKWARD COMPATABILITY REASONS
1157  *
1158  * @return @c true if the name of this SBML object is set, false
1159  * otherwise.
1160  */
1161 bool
isSetName() const1162 SBase::isSetName () const
1163 {
1164   return (getName().empty() == false);
1165 }
1166 
1167 
1168 bool
isSetIdAttribute() const1169 SBase::isSetIdAttribute () const
1170 {
1171   return (mId.empty() == false);
1172 }
1173 
1174 
1175 /*
1176  * @return @c true if the notes of this SBML object is set, false
1177  * otherwise.
1178  */
1179 bool
isSetNotes() const1180 SBase::isSetNotes () const
1181 {
1182   return (mNotes != NULL);
1183 }
1184 
1185 
1186 /*
1187  * @return @c true if the annotation of this SBML object is set,
1188  * false otherwise.
1189  */
1190 bool
isSetAnnotation() const1191 SBase::isSetAnnotation () const
1192 {
1193   const_cast <SBase *> (this)->syncAnnotation();
1194   return (mAnnotation != NULL);
1195 }
1196 
1197 
1198 /*
1199  * @return @c true if the sboTerm is set, false
1200  * otherwise.
1201  */
1202 bool
isSetSBOTerm() const1203 SBase::isSetSBOTerm () const
1204 {
1205   return (mSBOTerm != -1);
1206 }
1207 
1208 
1209 bool
isSetModelHistory()1210 SBase::isSetModelHistory()
1211 {
1212   return (mHistory != NULL);
1213 }
1214 
1215 
1216 /*
1217  * Sets the metaid field of the given SBML object to a copy of metaid.
1218  */
1219 int
setMetaId(const std::string & metaid)1220 SBase::setMetaId (const std::string& metaid)
1221 {
1222   if (getLevel() == 1)
1223   {
1224     return LIBSBML_UNEXPECTED_ATTRIBUTE;
1225   }
1226   else if (metaid.empty())
1227   {
1228     mMetaId.erase();
1229     // force any annotation to synchronize
1230     if (isSetAnnotation())
1231     {
1232       mCVTermsChanged = true;
1233     }
1234     return LIBSBML_OPERATION_SUCCESS;
1235   }
1236   else if (!(SyntaxChecker::isValidXMLID(metaid)))
1237   {
1238     return LIBSBML_INVALID_ATTRIBUTE_VALUE;
1239   }
1240   else
1241   {
1242     mMetaId = metaid;
1243     // force any annotation to synchronize
1244     if (isSetAnnotation())
1245     {
1246       mCVTermsChanged = true;
1247     }
1248     return LIBSBML_OPERATION_SUCCESS;
1249   }
1250 }
1251 
1252 
1253 int
setId(const std::string & sid)1254 SBase::setId (const std::string& sid)
1255 {
1256   if (getLevel() == 3 && getVersion() > 1)
1257   {
1258     // HACK to make a rule/initailassignment/eventassignment
1259     // in l3v2 not able to use this function
1260     int tc = getTypeCode();
1261     if (tc == SBML_ALGEBRAIC_RULE || tc == SBML_ASSIGNMENT_RULE ||
1262       tc == SBML_RATE_RULE || tc == SBML_INITIAL_ASSIGNMENT ||
1263       tc == SBML_EVENT_ASSIGNMENT)
1264     {
1265       return LIBSBML_USE_ID_ATTRIBUTE_FUNCTION;
1266     }
1267 
1268 
1269     if (!(SyntaxChecker::isValidInternalSId(sid)))
1270     {
1271       return LIBSBML_INVALID_ATTRIBUTE_VALUE;
1272     }
1273     else
1274     {
1275       mId = sid;
1276       return LIBSBML_OPERATION_SUCCESS;
1277     }
1278   }
1279   else
1280   {
1281     return LIBSBML_UNEXPECTED_ATTRIBUTE;
1282   }
1283 }
1284 
1285 
1286 int
setName(const std::string & name)1287 SBase::setName (const std::string& name)
1288 {
1289   if (getLevel() == 3 && getVersion() > 1)
1290   {
1291     mName = name;
1292     return LIBSBML_OPERATION_SUCCESS;
1293   }
1294   else
1295   {
1296     return LIBSBML_UNEXPECTED_ATTRIBUTE;
1297   }
1298 }
1299 
1300 
1301 int
setIdAttribute(const std::string & sid)1302 SBase::setIdAttribute (const std::string& sid)
1303 {
1304   if (!(SyntaxChecker::isValidInternalSId(sid)))
1305   {
1306     return LIBSBML_INVALID_ATTRIBUTE_VALUE;
1307   }
1308   else
1309   {
1310     mId = sid;
1311     return LIBSBML_OPERATION_SUCCESS;
1312   }
1313 }
1314 
1315 /*
1316  * Sets the annotation of this SBML object to a copy of annotation.
1317  */
1318 int
setAnnotation(const XMLNode * annotation)1319 SBase::setAnnotation (const XMLNode* annotation)
1320 {
1321   //
1322   // (*NOTICE*)
1323   //
1324   // syncAnnotation() must not be invoked in this function.
1325   //
1326   //
1327 
1328   if (annotation == NULL)
1329   {
1330     delete mAnnotation;
1331     mAnnotation = NULL;
1332   }
1333 
1334 
1335   //else if (!(math->isWellFormedASTNode()))
1336   //{
1337   //  return LIBSBML_INVALID_OBJECT;
1338   //}
1339   if (mAnnotation != annotation)
1340   {
1341     delete mAnnotation;
1342 
1343     // the annotation is an rdf annotation but the object has no metaid
1344     if (RDFAnnotationParser::hasRDFAnnotation(annotation) == true
1345       && (RDFAnnotationParser::hasCVTermRDFAnnotation(annotation) == true
1346       || RDFAnnotationParser::hasHistoryRDFAnnotation(annotation) == true)
1347       && isSetMetaId() == false)
1348     {
1349       mAnnotation = NULL;
1350       return LIBSBML_MISSING_METAID;
1351     }
1352     else
1353     {
1354       // check for annotation tags and add if necessary
1355       const string&  name = annotation->getName();
1356       if (name != "annotation")
1357       {
1358         XMLToken ann_t = XMLToken(XMLTriple("annotation", "", ""),
1359                                   XMLAttributes());
1360         mAnnotation = new XMLNode(ann_t);
1361 
1362         // The root node of the given XMLNode tree can be an empty XMLNode
1363         // (i.e. neither start, end, nor text XMLNode) if the given annotation was
1364         // converted from an XML string whose top level elements are neither
1365         // "html" nor "body" and not enclosed with <annotation>..</annotation> tags
1366         // (e.g. <foo xmlns:foo="...">..</foo><bar xmlns:bar="...">..</bar> )
1367         if (!annotation->isStart() && !annotation->isEnd() &&
1368                                       !annotation->isText())
1369         {
1370           for (unsigned int i=0; i < annotation->getNumChildren(); i++)
1371           {
1372             mAnnotation->addChild(annotation->getChild(i));
1373           }
1374         }
1375         else
1376         {
1377           mAnnotation->addChild(*annotation);
1378         }
1379       }
1380       else
1381       {
1382         mAnnotation = annotation->clone();
1383       }
1384     }
1385   }
1386 
1387   //
1388   // delete existing mCVTerms
1389   //
1390   // existing CVTerms (if any) needs to be deleted at any rate, otherwise
1391   // unsetAnnotation() ( setAnnotation(NULL) ) doesn't work as expected.
1392   // (These functions must clear all elements in an annotation.)
1393   //
1394 
1395   /* in L3 might be a model history */
1396   if (mHistory != NULL)
1397   {
1398     delete mHistory;
1399     mHistory = NULL;
1400   }
1401 
1402   if (mCVTerms != NULL)
1403   {
1404     // delete existing mCVTerms (if any)
1405     unsigned int size = mCVTerms->getSize();
1406     while (size--) delete static_cast<CVTerm*>( mCVTerms->remove(0) );
1407     delete mCVTerms;
1408     mCVTerms = NULL;
1409   }
1410 
1411 
1412   if(mAnnotation != NULL
1413         && RDFAnnotationParser::hasCVTermRDFAnnotation(mAnnotation))
1414   {
1415     // parse mAnnotation (if any) and set mCVTerms
1416     mCVTerms = new List();
1417     RDFAnnotationParser::parseRDFAnnotation(mAnnotation, mCVTerms);
1418     mCVTermsChanged = true;
1419   }
1420 
1421   if(getLevel() > 2 && mAnnotation != NULL
1422      && RDFAnnotationParser::hasHistoryRDFAnnotation(mAnnotation))
1423   {
1424     // parse mAnnotation (if any) and set mHistory
1425     mHistory = RDFAnnotationParser::parseRDFAnnotation(mAnnotation);
1426     mHistoryChanged = true;
1427   }
1428 
1429   for (size_t i=0; i < mPlugins.size(); i++)
1430   {
1431     mPlugins[i]->parseAnnotation(this, mAnnotation);
1432   }
1433 
1434 
1435   //mAnnotationChanged = true;
1436 
1437 
1438   return LIBSBML_OPERATION_SUCCESS;
1439 }
1440 
1441 /*
1442  * Sets the annotation (by string) of this SBML object to a copy of annotation.
1443  */
1444 int
setAnnotation(const std::string & annotation)1445 SBase::setAnnotation (const std::string& annotation)
1446 {
1447 
1448   int success = LIBSBML_OPERATION_FAILED;
1449 
1450   //
1451   // (*NOTICE*)
1452   //
1453   // syncAnnotation() must not be invoked in this function.
1454   //
1455   //
1456 
1457   if(annotation.empty())
1458   {
1459     unsetAnnotation();
1460     return LIBSBML_OPERATION_SUCCESS;
1461   }
1462 
1463   XMLNode* annt_xmln;
1464 
1465   // you might not have a document !!
1466   if (getSBMLDocument() != NULL)
1467   {
1468     XMLNamespaces* xmlns = getSBMLDocument()->getNamespaces();
1469     annt_xmln = XMLNode::convertStringToXMLNode(annotation,xmlns);
1470   }
1471   else
1472   {
1473     annt_xmln = XMLNode::convertStringToXMLNode(annotation);
1474   }
1475 
1476   if(annt_xmln != NULL)
1477   {
1478     success = setAnnotation(annt_xmln);
1479     delete annt_xmln;
1480   }
1481   return success;
1482 
1483 }
1484 
1485 
1486 /*
1487  * Appends annotation to the existing annotations.
1488  * This allows other annotations to be preserved whilst
1489  * adding additional information.
1490  */
1491 int
appendAnnotation(const XMLNode * annotation)1492 SBase::appendAnnotation (const XMLNode* annotation)
1493 {
1494   int success = LIBSBML_OPERATION_FAILED;
1495   unsigned int duplicates = 0;
1496 
1497   //
1498   // (*NOTICE*)
1499   //
1500   // syncAnnotation() doesn't need to be invoked in this function because
1501   // existing mCVTerm objects are properly merged in the following code.
1502   //
1503   // except when they have not been updated (ie CVTerm has been added but not synced
1504   // see bug reported via libsbml-team
1505   // https://www.pivotaltracker.com/story/show/166576120
1506 
1507   if (getNumCVTerms() > 0 && mAnnotation == NULL)
1508   {
1509     syncAnnotation();
1510   }
1511 
1512 
1513   if(annotation == NULL)
1514     return LIBSBML_OPERATION_SUCCESS;
1515 
1516   // the annotation is an rdf annotation but the object has no metaid
1517   if (RDFAnnotationParser::hasRDFAnnotation(annotation) == true
1518       && (RDFAnnotationParser::hasCVTermRDFAnnotation(annotation) == true
1519       || RDFAnnotationParser::hasHistoryRDFAnnotation(annotation) == true)
1520     && isSetMetaId() == false)
1521   {
1522     return LIBSBML_MISSING_METAID;
1523   }
1524 
1525   XMLNode* new_annotation = NULL;
1526   const string&  name = annotation->getName();
1527 
1528   // check for annotation tags and add if necessary
1529   if (name != "annotation")
1530   {
1531     XMLToken ann_t = XMLToken(XMLTriple("annotation", "", ""), XMLAttributes());
1532     new_annotation = new XMLNode(ann_t);
1533     new_annotation->addChild(*annotation);
1534   }
1535   else
1536   {
1537     new_annotation = annotation->clone();
1538   }
1539 
1540 
1541   if (mAnnotation != NULL)
1542   {
1543     // if mAnnotation is just <annotation/> need to tell
1544     // it to no longer be an end
1545     if (mAnnotation->isEnd())
1546     {
1547       mAnnotation->unsetEnd();
1548     }
1549 
1550 
1551     // create a list of existing top level ns
1552     IdList topLevelNs;
1553     unsigned int i = 0;
1554     for(i = 0; i < mAnnotation->getNumChildren(); i++)
1555     {
1556       topLevelNs.append(mAnnotation->getChild(i).getName());
1557     }
1558 
1559 
1560 
1561     for(i = 0; i < new_annotation->getNumChildren(); i++)
1562     {
1563       if (topLevelNs.contains(new_annotation->getChild(i).getName()) == false)
1564       {
1565         mAnnotation->addChild(new_annotation->getChild(i));
1566       }
1567       else
1568       {
1569         duplicates++;
1570       }
1571     }
1572 
1573     delete new_annotation;
1574 
1575     if (duplicates > 0)
1576     {
1577       success = LIBSBML_DUPLICATE_ANNOTATION_NS;
1578     }
1579     else
1580     {
1581       XMLNode *copy = mAnnotation->clone();
1582       success = setAnnotation(copy);
1583       delete copy;
1584     }
1585 
1586 
1587   }
1588   else
1589   {
1590     success = setAnnotation(new_annotation);
1591 
1592     delete new_annotation;
1593   }
1594 
1595   return success;
1596 }
1597 
1598 /*
1599  * Appends annotation (by string) to the existing annotations.
1600  * This allows other annotations to be preserved whilst
1601  * adding additional information.
1602  */
1603 int
appendAnnotation(const std::string & annotation)1604 SBase::appendAnnotation (const std::string& annotation)
1605 {
1606   //
1607   // (*NOTICE*)
1608   //
1609   // syncAnnotation() doesn't need to be invoked in this function because
1610   // existing mCVTerm objects are properly merged in the following code.
1611   //
1612   // except when they have not been updated (ie CVTerm has been added but not synced
1613   // see bug reported via libsbml-team
1614   // https://www.pivotaltracker.com/story/show/166576120
1615 
1616   if (getNumCVTerms() > 0 && mAnnotation == NULL)
1617   {
1618     syncAnnotation();
1619   }
1620 
1621   int success = LIBSBML_OPERATION_FAILED;
1622   XMLNode* annt_xmln;
1623   if (getSBMLDocument() != NULL)
1624   {
1625     XMLNamespaces* xmlns = getSBMLDocument()->getNamespaces();
1626     annt_xmln = XMLNode::convertStringToXMLNode(annotation,xmlns);
1627   }
1628   else
1629   {
1630     annt_xmln = XMLNode::convertStringToXMLNode(annotation);
1631   }
1632 
1633   if(annt_xmln != NULL)
1634   {
1635     success = appendAnnotation(annt_xmln);
1636     delete annt_xmln;
1637   }
1638 
1639   return success;
1640 }
1641 
1642 
1643 int
removeTopLevelAnnotationElement(const std::string & elementName,const std::string elementURI,bool removeEmpty)1644 SBase::removeTopLevelAnnotationElement(const std::string& elementName,
1645     const std::string elementURI, bool removeEmpty)
1646 {
1647 
1648   int success = LIBSBML_OPERATION_FAILED;
1649   if (mAnnotation == NULL)
1650   {
1651     success = LIBSBML_OPERATION_SUCCESS;
1652     return success;
1653   }
1654 
1655   int index = mAnnotation->getIndex(elementName);
1656   if (index < 0)
1657   {
1658     // the annotation does not have a child of this name
1659     success = LIBSBML_ANNOTATION_NAME_NOT_FOUND;
1660     return success;
1661   }
1662   else
1663   {
1664     // check uri matches
1665     if (elementURI.empty() == false)
1666     {
1667       XMLNode child = mAnnotation->getChild((unsigned int)index);
1668       std::string prefix = child.getPrefix();
1669 
1670       if (prefix.empty() == false
1671         && elementURI != child.getNamespaceURI(prefix))
1672       {
1673         success = LIBSBML_ANNOTATION_NS_NOT_FOUND;
1674         return success;
1675       }
1676       else
1677       {
1678         bool match = false;
1679         int n = 0;
1680 
1681         while (match == false && n < child.getNamespacesLength())
1682         {
1683           if (elementURI == child.getNamespaceURI(n))
1684           {
1685             match = true;
1686           }
1687           n++;
1688         }
1689 
1690         if (match == false)
1691         {
1692           success = LIBSBML_ANNOTATION_NS_NOT_FOUND;
1693           return success;
1694         }
1695       }
1696     }
1697 
1698     // remove the annotation at the index corresponding to the name
1699     delete mAnnotation->removeChild((unsigned int)index);
1700     if (removeEmpty && mAnnotation->getNumChildren() == 0)
1701     {
1702       delete mAnnotation;
1703       mAnnotation = NULL;
1704     }
1705 
1706     // check success
1707     if (mAnnotation == NULL || mAnnotation->getIndex(elementName) < 0)
1708     {
1709       success = LIBSBML_OPERATION_SUCCESS;
1710     }
1711   }
1712 
1713   return success;
1714 }
1715 
1716 
1717 int
replaceTopLevelAnnotationElement(const XMLNode * annotation)1718 SBase::replaceTopLevelAnnotationElement(const XMLNode* annotation)
1719 {
1720   int success = LIBSBML_OPERATION_FAILED;
1721   XMLNode * replacement = NULL;
1722   if (annotation->getName() == "annotation")
1723   {
1724     if (annotation->getNumChildren() != 1)
1725     {
1726       success = LIBSBML_INVALID_OBJECT;
1727       return success;
1728     }
1729     else
1730     {
1731       replacement = annotation->getChild(0).clone();
1732     }
1733   }
1734   else
1735   {
1736     replacement = annotation->clone();
1737   }
1738 
1739   success = removeTopLevelAnnotationElement(replacement->getName());
1740   if (success == LIBSBML_OPERATION_SUCCESS)
1741   {
1742     success = appendAnnotation(annotation);
1743   }
1744 
1745   delete (replacement);
1746 
1747   return success;
1748 }
1749 
1750 
1751 int
replaceTopLevelAnnotationElement(const std::string & annotation)1752 SBase::replaceTopLevelAnnotationElement(const std::string& annotation)
1753 {
1754   int success = LIBSBML_OPERATION_FAILED;
1755   XMLNode* annt_xmln;
1756   if (getSBMLDocument() != NULL)
1757   {
1758     XMLNamespaces* xmlns = getSBMLDocument()->getNamespaces();
1759     annt_xmln = XMLNode::convertStringToXMLNode(annotation,xmlns);
1760   }
1761   else
1762   {
1763     annt_xmln = XMLNode::convertStringToXMLNode(annotation);
1764   }
1765 
1766   if(annt_xmln != NULL)
1767   {
1768     success = replaceTopLevelAnnotationElement(annt_xmln);
1769   }
1770 
1771   delete annt_xmln;
1772 
1773   return success;
1774 }
1775 
1776 
1777 /*
1778  * Sets the notes of this SBML object to a copy of notes.
1779  */
1780 int
setNotes(const XMLNode * notes)1781 SBase::setNotes(const XMLNode* notes)
1782 {
1783   if (mNotes == notes)
1784   {
1785     return LIBSBML_OPERATION_SUCCESS;
1786   }
1787   else if (notes == NULL)
1788   {
1789     delete mNotes;
1790     mNotes = NULL;
1791     return LIBSBML_OPERATION_SUCCESS;
1792   }
1793 
1794   delete mNotes;
1795   const string&  name = notes->getName();
1796 
1797   /* check for notes tags and add if necessary */
1798 
1799   if (name == "notes")
1800   {
1801     mNotes = static_cast<XMLNode*>( notes->clone() );
1802   }
1803   else
1804   {
1805     XMLToken notes_t = XMLToken(XMLTriple("notes", "", ""),
1806                                 XMLAttributes());
1807     mNotes = new XMLNode(notes_t);
1808 
1809     // The root node of the given XMLNode tree can be an empty XMLNode
1810     // (i.e. neither start, end, nor text XMLNode) if the given notes was
1811     // converted from an XML string whose top level elements are neither
1812     // "html" nor "body" and not enclosed with <notes>..</notes> tag
1813     // (e.g. <p ...>..</p><br/>).
1814     if (!notes->isStart() && !notes->isEnd() && !notes->isText() )
1815     {
1816       for (unsigned int i=0; i < notes->getNumChildren(); i++)
1817       {
1818         if (mNotes->addChild(notes->getChild(i)) < 0)
1819         {
1820           return LIBSBML_OPERATION_FAILED;
1821         }
1822       }
1823     }
1824     else
1825     {
1826       if (mNotes->addChild(*notes) < 0)
1827         return LIBSBML_OPERATION_FAILED;
1828     }
1829   }
1830 
1831   // in L2v2 and beyond the XHTML content of notes is restricted
1832   // but I need the notes tag to use the function
1833   // so I havent tested it until now
1834   if (getLevel() > 2
1835     || (getLevel() == 2 && getVersion() > 1))
1836   {
1837     if (!SyntaxChecker::hasExpectedXHTMLSyntax(mNotes, getSBMLNamespaces()))
1838     {
1839       delete mNotes;
1840       mNotes = NULL;
1841       return LIBSBML_INVALID_OBJECT;
1842     }
1843   }
1844 
1845   return LIBSBML_OPERATION_SUCCESS;
1846 
1847 }
1848 
1849 /*
1850  * Sets the notes (by std::string) of this SBML object to a copy of notes.
1851  */
1852 int
setNotes(const std::string & notes,bool addXHTMLMarkup)1853 SBase::setNotes(const std::string& notes, bool addXHTMLMarkup)
1854 {
1855   int success = LIBSBML_OPERATION_FAILED;
1856 
1857   if (notes.empty())
1858   {
1859     success = unsetNotes();
1860   }
1861   else
1862   {
1863     XMLNode* notes_xmln;
1864 
1865     // you might not have a document !!
1866     if (getSBMLDocument() != NULL)
1867     {
1868       XMLNamespaces* xmlns = getSBMLDocument()->getNamespaces();
1869       notes_xmln = XMLNode::convertStringToXMLNode(notes,xmlns);
1870     }
1871     else
1872     {
1873       notes_xmln = XMLNode::convertStringToXMLNode(notes);
1874     }
1875 
1876     if(notes_xmln != NULL)
1877     {
1878       if (addXHTMLMarkup == true)
1879       {
1880         // user has specified that they want the markup added
1881         if (getLevel() > 2
1882           || (getLevel() == 2 && getVersion() > 1))
1883         {
1884           // just say the user passed a string that did not represent xhtml
1885           // the xmlnode will not get set as it is invalid
1886           if (notes_xmln->getNumChildren() == 0
1887             && notes_xmln->isStart() == false
1888             && notes_xmln->isEnd() == false
1889             && notes_xmln->isText() == true)
1890           {
1891             //create a parent node of xhtml type p
1892             XMLAttributes blank_att = XMLAttributes();
1893             XMLTriple triple = XMLTriple("p", "http://www.w3.org/1999/xhtml", "");
1894             XMLNamespaces xmlns = XMLNamespaces();
1895             xmlns.add("http://www.w3.org/1999/xhtml", "");
1896             XMLNode *xmlnode = new XMLNode(XMLToken(triple, blank_att, xmlns));
1897 
1898             // create a text node from the text given
1899             xmlnode->addChild(*notes_xmln);
1900             success = setNotes(xmlnode);
1901             delete xmlnode;
1902           }
1903           else
1904           {
1905             success = setNotes(notes_xmln);
1906           }
1907 
1908         }
1909         else
1910         {
1911           success = setNotes(notes_xmln);
1912         }
1913       }
1914       else
1915       {
1916         success = setNotes(notes_xmln);
1917       }
1918       delete notes_xmln;
1919     }
1920   }
1921   return success;
1922 }
1923 
1924 
1925 /*
1926  * Appends notes to the existing notes.
1927  * This allows other notes to be preserved whilst
1928  * adding additional information.
1929  */
1930 int
appendNotes(const XMLNode * notes)1931 SBase::appendNotes(const XMLNode* notes)
1932 {
1933   int success = LIBSBML_OPERATION_FAILED;
1934   if(notes == NULL)
1935   {
1936     return LIBSBML_OPERATION_SUCCESS;
1937   }
1938 
1939   const string&  name = notes->getName();
1940 
1941   // The content of notes in SBML can consist only of the following
1942   // possibilities:
1943   //
1944   //  1. A complete XHTML document (minus the XML and DOCTYPE
1945   //     declarations), that is, XHTML content beginning with the
1946   //     html tag.
1947   //     (_NotesType is _ANotesHTML.)
1948   //
1949   //  2. The body element from an XHTML document.
1950   //     (_NotesType is _ANotesBody.)
1951   //
1952   //  3. Any XHTML content that would be permitted within a body
1953   //     element, each one must declare the XML namespace separately.
1954   //     (_NotesType is _ANotesAny.)
1955   //
1956 
1957   typedef enum { _ANotesHTML, _ANotesBody, _ANotesAny } _NotesType;
1958 
1959   _NotesType addedNotesType = _ANotesAny;
1960   XMLNode   addedNotes;
1961 
1962   //------------------------------------------------------------
1963   //
1964   // STEP1 : identifies the type of the given notes
1965   //
1966   //------------------------------------------------------------
1967 
1968   if (name == "notes")
1969   {
1970     /* check for notes tags on the added notes and strip if present and
1971        the notes tag has "html" or "body" element */
1972 
1973     if (notes->getNumChildren() > 0)
1974     {
1975       // notes->getChild(0) must be "html", "body", or any XHTML
1976       // element that would be permitted within a "body" element
1977       // (e.g. <p>..</p>,  <br>..</br> and so forth).
1978 
1979       const string& cname = notes->getChild(0).getName();
1980 
1981       if (cname == "html")
1982       {
1983         addedNotes = notes->getChild(0);
1984         addedNotesType = _ANotesHTML;
1985       }
1986       else if (cname == "body")
1987       {
1988         addedNotes = notes->getChild(0);
1989         addedNotesType = _ANotesBody;
1990       }
1991       else
1992       {
1993         // the notes tag must NOT be stripped if notes->getChild(0) node
1994         // is neither "html" nor "body" element because the children of
1995         // the addedNotes will be added to the curNotes later if the node
1996         // is neither "html" nor "body".
1997         addedNotes = *notes;
1998         addedNotesType = _ANotesAny;
1999       }
2000     }
2001     else
2002     {
2003       // the given notes is empty
2004       return LIBSBML_OPERATION_SUCCESS;
2005     }
2006   }
2007   else
2008   {
2009     // if the XMLNode argument notes has been created from a string and
2010     // it is a set of subelements there may be a single empty node
2011     // as parent - leaving this in doesnt affect the writing out of notes
2012     // but messes up the check for correct syntax
2013     if (!notes->isStart() && !notes->isEnd() && !notes->isText() )
2014     {
2015       if (notes->getNumChildren() > 0)
2016       {
2017         addedNotes = *notes;
2018         addedNotesType = _ANotesAny;
2019       }
2020       else
2021       {
2022         // the given notes is empty
2023         return LIBSBML_OPERATION_SUCCESS;
2024       }
2025     }
2026     else
2027     {
2028       if (name == "html")
2029       {
2030         addedNotes = *notes;
2031         addedNotesType = _ANotesHTML;
2032       }
2033       else if (name == "body")
2034       {
2035         addedNotes = *notes;
2036         addedNotesType = _ANotesBody;
2037       }
2038       else
2039       {
2040         // The given notes node needs to be added to a parent node
2041         // if the node is neither "html" nor "body" element because the
2042         // children of addedNotes will be added to the curNotes later if the
2043         // node is neither "html" nor "body" (i.e. any XHTML element that
2044         // would be permitted within a "body" element)
2045         addedNotes.addChild(*notes);
2046         addedNotesType = _ANotesAny;
2047       }
2048     }
2049   }
2050 
2051   //
2052   // checks the addedNotes of "html" if the html tag contains "head" and
2053   // "body" tags which must be located in this order.
2054   //
2055   if (addedNotesType == _ANotesHTML)
2056   {
2057     if ((addedNotes.getNumChildren() != 2) ||
2058         ( (addedNotes.getChild(0).getName() != "head") ||
2059           (addedNotes.getChild(1).getName() != "body")
2060         )
2061        )
2062     {
2063       return LIBSBML_INVALID_OBJECT;
2064     }
2065   }
2066 
2067   // check whether notes is valid xhtml
2068   if (getLevel() > 2
2069     || (getLevel() == 2 && getVersion() > 1))
2070   {
2071     XMLNode tmpNotes(XMLTriple("notes","",""), XMLAttributes());
2072 
2073     if (addedNotesType == _ANotesAny)
2074     {
2075       for (unsigned int i=0; i < addedNotes.getNumChildren(); i++)
2076       {
2077         tmpNotes.addChild(addedNotes.getChild(i));
2078       }
2079     }
2080     else
2081     {
2082       tmpNotes.addChild(addedNotes);
2083     }
2084 
2085     if (!SyntaxChecker::hasExpectedXHTMLSyntax(&tmpNotes, getSBMLNamespaces()))
2086     {
2087       return LIBSBML_INVALID_OBJECT;
2088     }
2089   }
2090 
2091 
2092   if ( mNotes != NULL )
2093   {
2094     //------------------------------------------------------------
2095     //
2096     //  STEP2: identifies the type of the existing notes
2097     //
2098     //------------------------------------------------------------
2099 
2100     _NotesType curNotesType   = _ANotesAny;
2101     XMLNode&  curNotes = *mNotes;
2102 
2103     // curNotes.getChild(0) must be "html", "body", or any XHTML
2104     // element that would be permitted within a "body" element .
2105 
2106     const string& cname = curNotes.getChild(0).getName();
2107 
2108     if (cname == "html")
2109     {
2110       XMLNode& curHTML = curNotes.getChild(0);
2111       //
2112       // checks the curHTML if the html tag contains "head" and "body" tags
2113       // which must be located in this order, otherwise nothing will be done.
2114       //
2115       if ((curHTML.getNumChildren() != 2) ||
2116           ( (curHTML.getChild(0).getName() != "head") ||
2117             (curHTML.getChild(1).getName() != "body")
2118           )
2119          )
2120       {
2121         return LIBSBML_INVALID_OBJECT;
2122       }
2123       curNotesType = _ANotesHTML;
2124     }
2125     else if (cname == "body")
2126     {
2127       curNotesType = _ANotesBody;
2128     }
2129     else
2130     {
2131       curNotesType = _ANotesAny;
2132     }
2133 
2134     /*
2135      * BUT we also have the issue of the rules relating to notes
2136      * contents and where to add them ie we cannot add a second body element
2137      * etc...
2138      */
2139 
2140     //------------------------------------------------------------
2141     //
2142     //  STEP3: appends the given notes to the current notes
2143     //
2144     //------------------------------------------------------------
2145 
2146     unsigned int i;
2147 
2148     if (curNotesType == _ANotesHTML)
2149     {
2150       XMLNode& curHTML = curNotes.getChild(0);
2151       XMLNode& curBody = curHTML.getChild(1);
2152 
2153       if (addedNotesType == _ANotesHTML)
2154       {
2155         // adds the given html tag to the current html tag
2156 
2157         XMLNode& addedBody = addedNotes.getChild(1);
2158 
2159         for (i=0; i < addedBody.getNumChildren(); i++)
2160         {
2161           if (curBody.addChild(addedBody.getChild(i)) < 0 )
2162             return LIBSBML_OPERATION_FAILED;
2163         }
2164       }
2165       else if ((addedNotesType == _ANotesBody)
2166              || (addedNotesType == _ANotesAny))
2167       {
2168         // adds the given body or other tag (permitted in the body) to the current
2169         // html tag
2170 
2171         for (i=0; i < addedNotes.getNumChildren(); i++)
2172         {
2173           if (curBody.addChild(addedNotes.getChild(i)) < 0 )
2174             return LIBSBML_OPERATION_FAILED;
2175         }
2176       }
2177       success = LIBSBML_OPERATION_SUCCESS;
2178     }
2179     else if (curNotesType == _ANotesBody)
2180     {
2181       if (addedNotesType == _ANotesHTML)
2182       {
2183         // adds the given html tag to the current body tag
2184 
2185         XMLNode  addedHTML(addedNotes);
2186         XMLNode& addedBody = addedHTML.getChild(1);
2187         XMLNode& curBody   = curNotes.getChild(0);
2188 
2189         for (i=0; i < curBody.getNumChildren(); i++)
2190         {
2191           addedBody.insertChild(i,curBody.getChild(i));
2192         }
2193 
2194         curNotes.removeChildren();
2195         if (curNotes.addChild(addedHTML) < 0)
2196           return LIBSBML_OPERATION_FAILED;
2197       }
2198       else if ((addedNotesType == _ANotesBody) || (addedNotesType == _ANotesAny))
2199       {
2200         // adds the given body or other tag (permitted in the body) to the current
2201         // body tag
2202 
2203         XMLNode& curBody = curNotes.getChild(0);
2204 
2205         for (i=0; i < addedNotes.getNumChildren(); i++)
2206         {
2207           if (curBody.addChild(addedNotes.getChild(i)) < 0)
2208             return LIBSBML_OPERATION_FAILED;
2209         }
2210       }
2211       success = LIBSBML_OPERATION_SUCCESS;
2212     }
2213     else if (curNotesType == _ANotesAny)
2214     {
2215       if (addedNotesType == _ANotesHTML)
2216       {
2217         // adds the given html tag to the current any tag permitted in the body.
2218 
2219         XMLNode  addedHTML(addedNotes);
2220         XMLNode& addedBody = addedHTML.getChild(1);
2221 
2222         for (i=0; i < curNotes.getNumChildren(); i++)
2223         {
2224           addedBody.insertChild(i,curNotes.getChild(i));
2225         }
2226 
2227         curNotes.removeChildren();
2228         if (curNotes.addChild(addedHTML) < 0)
2229           return LIBSBML_OPERATION_FAILED;
2230       }
2231       else if (addedNotesType == _ANotesBody)
2232       {
2233         // adds the given body tag to the current any tag permitted in the body.
2234 
2235         XMLNode addedBody(addedNotes);
2236 
2237         for (i=0; i < curNotes.getNumChildren(); i++)
2238         {
2239           addedBody.insertChild(i,curNotes.getChild(i));
2240         }
2241 
2242         curNotes.removeChildren();
2243         if (curNotes.addChild(addedBody) < 0)
2244           return LIBSBML_OPERATION_FAILED;
2245       }
2246       else if (addedNotesType == _ANotesAny)
2247       {
2248         // adds the given any tag permitted in the boy to that of the current
2249         // any tag.
2250 
2251         for (i=0; i < addedNotes.getNumChildren(); i++)
2252         {
2253           if (curNotes.addChild(addedNotes.getChild(i)) < 0)
2254             return LIBSBML_OPERATION_FAILED;
2255         }
2256       }
2257       success = LIBSBML_OPERATION_SUCCESS;
2258     }
2259   }
2260   else // if (mNotes == NULL)
2261   {
2262     // setNotes accepts XMLNode with/without top level notes tags.
2263     success = setNotes(notes);
2264   }
2265 
2266   return success;
2267 }
2268 
2269 /*
2270  * Appends notes (by string) to the existing notes.
2271  * This allows other notes to be preserved whilst
2272  * adding additional information.
2273  */
2274 int
appendNotes(const std::string & notes)2275 SBase::appendNotes(const std::string& notes)
2276 {
2277   int success = LIBSBML_OPERATION_FAILED;
2278   if (notes.empty())
2279   {
2280     return LIBSBML_OPERATION_SUCCESS;
2281   }
2282 
2283   XMLNode* notes_xmln;
2284   // you might not have a document !!
2285   if (getSBMLDocument() != NULL)
2286   {
2287       XMLNamespaces* xmlns = getSBMLDocument()->getNamespaces();
2288       notes_xmln = XMLNode::convertStringToXMLNode(notes,xmlns);
2289   }
2290   else
2291   {
2292       notes_xmln = XMLNode::convertStringToXMLNode(notes);
2293   }
2294 
2295   if(notes_xmln != NULL)
2296   {
2297     success = appendNotes(notes_xmln);
2298     delete notes_xmln;
2299   }
2300   return success;
2301 }
2302 
2303 
2304 int
setModelHistory(ModelHistory * history)2305 SBase::setModelHistory(ModelHistory * history)
2306 {
2307   /* ModelHistory is only allowed on Model in L2
2308    * but on any element in L3
2309    */
2310   if (getLevel() < 3)
2311   {
2312     if (getTypeCode() != SBML_MODEL)
2313     {
2314       return LIBSBML_UNEXPECTED_ATTRIBUTE;
2315     }
2316   }
2317   // shouldnt add a history to an object with no metaid
2318   if (!isSetMetaId())
2319   {
2320     return LIBSBML_MISSING_METAID;
2321   }
2322 
2323   if (mHistory == history)
2324   {
2325     return LIBSBML_OPERATION_SUCCESS;
2326   }
2327   else if (history == NULL)
2328   {
2329     delete mHistory;
2330     mHistory = NULL;
2331     mHistoryChanged = true;
2332     return LIBSBML_OPERATION_SUCCESS;
2333   }
2334   else if (!(history->hasRequiredAttributes()))
2335   {
2336     delete mHistory;
2337     mHistory = NULL;
2338     return LIBSBML_INVALID_OBJECT;
2339   }
2340   else
2341   {
2342     delete mHistory;
2343     mHistory = static_cast<ModelHistory*>( history->clone() );
2344     mHistoryChanged = true;
2345     return LIBSBML_OPERATION_SUCCESS;
2346   }
2347 }
2348 
2349 
2350 /** @cond doxygenLibsbmlInternal */
2351 /*
2352  * Sets the parent SBMLDocument of this SBML object.
2353  */
2354 void
setSBMLDocument(SBMLDocument * d)2355 SBase::setSBMLDocument (SBMLDocument* d)
2356 {
2357   mSBML = d;
2358 
2359   //
2360   // (EXTENSION)
2361   //
2362   for (size_t i=0; i < mPlugins.size(); i++)
2363   {
2364     mPlugins[i]->setSBMLDocument(d);
2365   }
2366 }
2367 
2368 
2369 /*
2370   * Sets the parent SBML object of this SBML object.
2371   *
2372   * @param sb the SBML object to use.
2373   */
2374 void
connectToParent(SBase * parent)2375 SBase::connectToParent (SBase* parent)
2376 {
2377   mParentSBMLObject = parent;
2378   if (mParentSBMLObject)
2379   {
2380 #if 0
2381     cout << "[DEBUG] connectToParent " << this << " (parent) " << SBMLTypeCode_toString(parent->getTypeCode(),"core")
2382          << " " << parent->getSBMLDocument() << endl;
2383 #endif
2384     setSBMLDocument(mParentSBMLObject->getSBMLDocument());
2385   }
2386   else
2387   {
2388     setSBMLDocument(0);
2389   }
2390   for (unsigned int p=0; p<mPlugins.size(); p++) {
2391     mPlugins[p]->connectToParent(this);
2392   }
2393 }
2394 
2395 
2396 /*
2397  * Sets this SBML object to child SBML objects (if any).
2398  * (Creates a child-parent relationship by the parent)
2399  *
2400  * Subclasses must override this function if they define
2401  * one ore more child elements.
2402  * Basically, this function needs to be called in
2403  * constructors, copy constructors and assignment operators.
2404  */
2405 void
connectToChild()2406 SBase::connectToChild()
2407 {
2408   for (size_t p=0; p<mPlugins.size(); p++) {
2409     mPlugins[p]->connectToParent(this);
2410   }
2411 }
2412 /** @endcond */
2413 
2414 SBase*
getAncestorOfType(int type,const std::string & pkgName)2415 SBase::getAncestorOfType(int type, const std::string& pkgName)
2416 {
2417   if (pkgName == "core" && type == SBML_DOCUMENT)
2418     return getSBMLDocument();
2419 
2420   SBase *child;
2421   SBase *parent = getParentSBMLObject();
2422 
2423   while ( parent != NULL &&
2424           !( parent->getPackageName() == "core" &&
2425              parent->getTypeCode() == SBML_DOCUMENT )
2426         )
2427   {
2428     if (parent->getTypeCode() == type && parent->getPackageName() == pkgName)
2429       return parent;
2430     else
2431     {
2432       child = parent;
2433       parent = child->getParentSBMLObject();
2434     }
2435   }
2436 
2437   // if we get here we havent found an ancestor of this type
2438   return NULL;
2439 
2440 }
2441 
2442 
2443 const SBase*
getAncestorOfType(int type,const std::string pkgName) const2444 SBase::getAncestorOfType(int type, const std::string pkgName) const
2445 {
2446   if (pkgName == "core" && type == SBML_DOCUMENT)
2447     return getSBMLDocument();
2448 
2449   const SBase *child;
2450   const SBase *parent = getParentSBMLObject();
2451 
2452   while ( parent != NULL &&
2453           !( parent->getPackageName() == "core" &&
2454              parent->getTypeCode() == SBML_DOCUMENT )
2455         )
2456   {
2457     if (parent->getTypeCode() == type && parent->getPackageName() == pkgName)
2458       return parent;
2459     else
2460     {
2461       child = parent;
2462       parent = child->getParentSBMLObject();
2463     }
2464   }
2465 
2466   // if we get here we havent found an ancestor of this type
2467   return NULL;
2468 
2469 }
2470 
2471 
2472 /*
2473  * Sets the sboTerm field to value.
2474  */
2475 int
setSBOTerm(int value)2476 SBase::setSBOTerm (int value)
2477 {
2478   if (getLevel() < 2 || (getLevel() == 2 && getVersion() < 2))
2479   {
2480     mSBOTerm = -1;
2481     return LIBSBML_UNEXPECTED_ATTRIBUTE;
2482   }
2483   else
2484   {
2485     if ( !SBO::checkTerm(value) )
2486     {
2487       mSBOTerm = -1;
2488       return LIBSBML_INVALID_ATTRIBUTE_VALUE;
2489     }
2490     mSBOTerm = value;
2491     return LIBSBML_OPERATION_SUCCESS;
2492   }
2493 }
2494 
2495 /*
2496  * Sets the sboTerm field to value converted from the given string.
2497  */
2498 int
setSBOTerm(const std::string & sboid)2499 SBase::setSBOTerm (const std::string &sboid)
2500 {
2501   return setSBOTerm(SBO::stringToInt(sboid));
2502 }
2503 
2504 
2505 /*
2506  * Sets the namespaces relevant of this SBML object.
2507  *
2508  * @param xmlns the namespaces to set.
2509  */
2510 int
setNamespaces(XMLNamespaces * xmlns)2511 SBase::setNamespaces(XMLNamespaces* xmlns)
2512 {
2513   if (xmlns == NULL)
2514   {
2515     mSBMLNamespaces->setNamespaces(NULL);
2516     return LIBSBML_OPERATION_SUCCESS;
2517   }
2518   else
2519   {
2520     mSBMLNamespaces->setNamespaces(xmlns);
2521     return LIBSBML_OPERATION_SUCCESS;
2522   }
2523 }
2524 
2525 
2526 
2527 /*
2528  * Unsets the metaid of this SBML object.
2529  */
2530 int
unsetMetaId()2531 SBase::unsetMetaId ()
2532 {
2533   /* only in L2 onwards */
2534   if (getLevel() < 2)
2535   {
2536     return LIBSBML_UNEXPECTED_ATTRIBUTE;
2537   }
2538 
2539   mMetaId.erase();
2540 
2541   if (mMetaId.empty())
2542   {
2543     return LIBSBML_OPERATION_SUCCESS;
2544   }
2545   else
2546   {
2547     return LIBSBML_OPERATION_FAILED;
2548   }
2549 }
2550 
2551 
2552 /*
2553  * Unsets the id of this SBML object.
2554  */
2555 int
unsetId()2556 SBase::unsetId ()
2557 {
2558   if (getLevel() == 3 && getVersion() > 1)
2559   {
2560     mId.erase();
2561     // HACK to make a rule in l3v2 not able to use this function
2562     int tc = getTypeCode();
2563     if (tc == SBML_ALGEBRAIC_RULE || tc == SBML_ASSIGNMENT_RULE ||
2564       tc == SBML_RATE_RULE || tc == SBML_INITIAL_ASSIGNMENT ||
2565       tc == SBML_EVENT_ASSIGNMENT)
2566     {
2567       return LIBSBML_USE_ID_ATTRIBUTE_FUNCTION;
2568     }
2569 
2570 
2571     if (mId.empty())
2572     {
2573       return LIBSBML_OPERATION_SUCCESS;
2574     }
2575     else
2576     {
2577       return LIBSBML_OPERATION_FAILED;
2578     }
2579   }
2580   else
2581   {
2582     return LIBSBML_OPERATION_FAILED;
2583   }
2584 }
2585 
2586 
2587 int
unsetIdAttribute()2588 SBase::unsetIdAttribute ()
2589 {
2590   mId.erase();
2591 
2592   if (mId.empty())
2593   {
2594     return LIBSBML_OPERATION_SUCCESS;
2595   }
2596   else
2597   {
2598     return LIBSBML_OPERATION_FAILED;
2599   }
2600 }
2601 
2602 
2603 /*
2604  * Unsets the name of this SBML object.
2605  */
2606 int
unsetName()2607 SBase::unsetName ()
2608 {
2609   if (getLevel() == 3 && getVersion() > 1)
2610   {
2611     mName.erase();
2612 
2613     if (mName.empty())
2614     {
2615       return LIBSBML_OPERATION_SUCCESS;
2616     }
2617     else
2618     {
2619       return LIBSBML_OPERATION_FAILED;
2620     }
2621   }
2622   else
2623   {
2624     return LIBSBML_OPERATION_FAILED;
2625   }
2626 }
2627 
2628 
2629 /*
2630  * Unsets the notes of this SBML object.
2631  */
2632 int
unsetNotes()2633 SBase::unsetNotes ()
2634 {
2635   delete mNotes;
2636   mNotes = NULL;
2637   return LIBSBML_OPERATION_SUCCESS;
2638 }
2639 
2640 
2641 /*
2642  * Unsets the annotation of this SBML object.
2643  */
2644 int
unsetAnnotation()2645 SBase::unsetAnnotation ()
2646 {
2647   XMLNode* empty = NULL;
2648   return setAnnotation(empty);
2649 }
2650 
2651 
2652 /*
2653  * Unsets the sboTerm of this SBML object.
2654  */
2655 int
unsetSBOTerm()2656 SBase::unsetSBOTerm ()
2657 {
2658   if (getLevel() < 2 || (getLevel() == 2 && getVersion() < 2))
2659   {
2660     mSBOTerm = -1;
2661     return LIBSBML_UNEXPECTED_ATTRIBUTE;
2662   }
2663   else
2664   {
2665     mSBOTerm = -1;
2666     return LIBSBML_OPERATION_SUCCESS;
2667   }
2668 }
2669 
2670 
2671 /** @cond doxygenLibsbmlInternal */
removeDuplicatedResources(CVTerm * term,QualifierType_t type)2672 void SBase::removeDuplicatedResources(CVTerm *term, QualifierType_t type)
2673 {
2674   int length = term->getResources()->getLength();
2675   if (type == BIOLOGICAL_QUALIFIER)
2676   {
2677     BiolQualifierType_t biolQual = BQB_UNKNOWN;
2678     for (int p = length-1; p > -1; p--)
2679     {
2680       biolQual = getResourceBiologicalQualifier(term->getResources()->getValue(p));
2681       if (biolQual != BQB_UNKNOWN)
2682       {
2683         /* resource is already present
2684         * - dont want to add again;
2685         * so delete it from set to be added
2686         */
2687         term->removeResource(term->getResources()->getValue(p));
2688       }
2689     }
2690   }
2691   else if (type == MODEL_QUALIFIER)
2692   {
2693     ModelQualifierType_t modelQual = BQM_UNKNOWN;
2694     for (int p = length-1; p > -1; p--)
2695     {
2696       modelQual = getResourceModelQualifier(term->getResources()->getValue(p));
2697       if (modelQual != BQM_UNKNOWN)
2698       {
2699         /* resource is already present
2700         * - dont want to add again;
2701         * so delete it from set to be added
2702         */
2703         term->removeResource(term->getResources()->getValue(p));
2704       }
2705     }
2706   }
2707 }
2708 /** @endcond */
2709 
2710 /** @cond doxygenLibsbmlInternal */
addTermToExistingBag(CVTerm * term,QualifierType_t type)2711 int SBase::addTermToExistingBag(CVTerm *term, QualifierType_t type )
2712 {
2713   unsigned int added = 0;
2714   unsigned int length = mCVTerms->getSize();
2715 
2716   CVTerm* nthTerm = NULL;
2717 
2718   if (length == 0) return (int)added;
2719 
2720   if (type == BIOLOGICAL_QUALIFIER)
2721   {
2722     BiolQualifierType_t biol = term->getBiologicalQualifierType();
2723 
2724     for (int n = (int)length -1; n >= 0  && added == 0; n--)
2725     {
2726       nthTerm = static_cast <CVTerm *>(mCVTerms->get((unsigned int)n));
2727 
2728       if (nthTerm != NULL && biol == nthTerm->getBiologicalQualifierType())
2729       {
2730         for (int r = 0; r < term->getResources()->getLength(); r++)
2731         {
2732           nthTerm->addResource(
2733             term->getResources()->getValue(r));
2734         }
2735         added = 1;
2736       }
2737     }
2738   }
2739   else if (type == MODEL_QUALIFIER)
2740   {
2741     ModelQualifierType_t model = term->getModelQualifierType();
2742 
2743     for (unsigned int n = 0; n < length && added == 0; n++)
2744     {
2745       nthTerm = static_cast <CVTerm *>(mCVTerms->get(n));
2746 
2747       if (nthTerm != NULL && model == nthTerm->getModelQualifierType())
2748       {
2749         for (int r = 0; r < term->getResources()->getLength(); r++)
2750         {
2751           nthTerm->addResource(
2752             term->getResources()->getValue(r));
2753         }
2754         added = 1;
2755       }
2756     }
2757   }
2758   return (int)added;
2759 }
2760 /** @endcond */
2761 
2762 /*
2763  * Adds a copy of the given CVTerm to this SBML object.
2764  */
2765 int
addCVTerm(CVTerm * term,bool newBag)2766 SBase::addCVTerm(CVTerm * term, bool newBag)
2767 {
2768   unsigned int added = 0;
2769   // shouldnt add a CVTerm to an object with no metaid
2770   if (!isSetMetaId())
2771   {
2772     return LIBSBML_MISSING_METAID;
2773   }
2774 
2775   if (term == NULL)
2776   {
2777     return LIBSBML_OPERATION_FAILED;
2778   }
2779   else if (!term->hasRequiredAttributes())
2780   {
2781     return LIBSBML_INVALID_OBJECT;
2782   }
2783 
2784   /* clone the term to be added so that I can adjust
2785    * which resources are actually added
2786    */
2787   CVTerm * copyTerm = term->clone();
2788 
2789   if (mCVTerms == NULL)
2790   {
2791     mCVTerms = new List();
2792     mCVTerms->add((void *) term->clone());
2793   }
2794   else if (mCVTerms->getSize() == 0)
2795   {
2796     mCVTerms->add((void *) term->clone());
2797   }
2798   else
2799   {
2800     /* check whether the resources are already listed */
2801     QualifierType_t type = copyTerm->getQualifierType();
2802     removeDuplicatedResources(copyTerm, type);
2803 
2804     /* if the qualifier of the term being added is already present
2805      * add to the list of resources for that qualifier
2806      */
2807     if (newBag == false)
2808     {
2809       added = (unsigned int)addTermToExistingBag(copyTerm, type);
2810     }
2811 
2812     if (added == 0 && copyTerm->getResources()->getLength() > 0)
2813     {
2814       /* no matching copyTerms already in list */
2815       mCVTerms->add((void *) copyTerm->clone());
2816     }
2817 
2818   }
2819 
2820   delete copyTerm;
2821   mCVTermsChanged = true;
2822   return LIBSBML_OPERATION_SUCCESS;
2823 }
2824 
2825 
2826 /*
2827  * @return the list of CVTerms for this SBML object.
2828  */
2829 List*
getCVTerms()2830 SBase::getCVTerms()
2831 {
2832   return mCVTerms;
2833 }
2834 
2835 
2836 /*
2837  * @return the list of CVTerms for this SBML object.
2838  */
2839 List*
getCVTerms() const2840 SBase::getCVTerms() const
2841 {
2842   return mCVTerms;
2843 }
2844 
2845 /*
2846  * Returns the number of CVTerm objects in the annotations of this SBML
2847  * object.
2848  *
2849  * @return the number of CVTerms for this SBML object.
2850  */
2851 unsigned int
getNumCVTerms()2852 SBase::getNumCVTerms()
2853 {
2854   if (mCVTerms != NULL)
2855   {
2856     return mCVTerms->getSize();
2857   }
2858   else
2859   {
2860     return 0;
2861   }
2862 }
2863 
2864 
2865 /*
2866  * Returns the nth CVTerm in the list of CVTerms of this SBML
2867  * object.
2868  *
2869  * @param n unsigned int the index of the CVTerm to retrieve.
2870  *
2871  * @return the nth CVTerm in the list of CVTerms for this SBML object.
2872  */
2873 CVTerm*
getCVTerm(unsigned int n)2874 SBase::getCVTerm(unsigned int n)
2875 {
2876   return (mCVTerms) ? static_cast <CVTerm*> (mCVTerms->get(n)) : NULL;
2877 }
2878 
2879 
2880 /*
2881  * Clears the list of CVTerms of this SBML
2882  * object.
2883  */
2884 int
unsetCVTerms()2885 SBase::unsetCVTerms()
2886 {
2887   if (mCVTerms != NULL)
2888   {
2889     unsigned int size = mCVTerms->getSize();
2890     while (size--) delete static_cast<CVTerm*>( mCVTerms->remove(0) );
2891     delete mCVTerms;
2892     mCVTermsChanged = true;
2893   }
2894   mCVTerms = NULL;
2895 
2896   if (mCVTerms != NULL)
2897     return LIBSBML_OPERATION_FAILED;
2898   else
2899     return LIBSBML_OPERATION_SUCCESS;
2900 }
2901 
2902 
2903 int
unsetModelHistory()2904 SBase::unsetModelHistory()
2905 {
2906   if (mHistory != NULL)
2907     mHistoryChanged = true;
2908 
2909   delete mHistory;
2910   mHistory = NULL;
2911 
2912   /* ModelHistory is only allowed on Model in L2
2913    * but on any element in L3
2914    */
2915   if (getLevel() < 3 && getTypeCode() != SBML_MODEL)
2916   {
2917     return LIBSBML_UNEXPECTED_ATTRIBUTE;
2918   }
2919 
2920   if (mHistory != NULL)
2921   {
2922     return LIBSBML_OPERATION_FAILED;
2923   }
2924   else
2925   {
2926     return LIBSBML_OPERATION_SUCCESS;
2927   }
2928 }
2929 
2930 
2931 /*
2932  * Returns the BiologicalQualifier associated with this resource,
2933  * an empty string if the resource does not exist.
2934  *
2935  * @param resource string representing the resource; e.g.,
2936  * "http://www.geneontology.org/#GO:0005892".
2937  *
2938  * @return the BiolQualifierType_t associated with the resource
2939  */
2940 BiolQualifierType_t
getResourceBiologicalQualifier(std::string resource)2941 SBase::getResourceBiologicalQualifier(std::string resource)
2942 {
2943   if (mCVTerms != NULL)
2944   {
2945     for (unsigned int n = 0; n < mCVTerms->getSize(); n++)
2946     {
2947       // does this term have a biological qualifier
2948       if (static_cast <CVTerm *>(mCVTerms->get(n))->getQualifierType()
2949                                                               == BIOLOGICAL_QUALIFIER)
2950       {
2951         // check whether given resource is present
2952         for (int r = 0;
2953           r < static_cast <CVTerm *>(mCVTerms->get(n))->getResources()->getLength(); r++)
2954         {
2955           if (resource ==
2956             static_cast <CVTerm *>(mCVTerms->get(n))->getResources()->getValue(r))
2957           {
2958             return static_cast <CVTerm *>(mCVTerms->get(n))->getBiologicalQualifierType();
2959           }
2960         }
2961       }
2962     }
2963   }
2964 
2965   return BQB_UNKNOWN;
2966 }
2967 
2968 /*
2969  * Returns the ModelQualifier associated with this resource,
2970  * an empty string if the resource does not exist.
2971  *
2972  * @param resource string representing the resource; e.g.,
2973  * "http://www.geneontology.org/#GO:0005892".
2974  *
2975  * @return the ModelQualifierType_t associated with the resource
2976  */
2977 ModelQualifierType_t
getResourceModelQualifier(std::string resource)2978 SBase::getResourceModelQualifier(std::string resource)
2979 {
2980   if (mCVTerms != NULL)
2981   {
2982     for (unsigned int n = 0; n < mCVTerms->getSize(); n++)
2983     {
2984       // does this term have a biological qualifier
2985       if (static_cast <CVTerm *>(mCVTerms->get(n))->getQualifierType()
2986                                                               == MODEL_QUALIFIER)
2987       {
2988         // check whether given resource is present
2989         for (int r = 0;
2990           r < static_cast <CVTerm *>(mCVTerms->get(n))->getResources()->getLength(); r++)
2991         {
2992           if (resource ==
2993             static_cast <CVTerm *>(mCVTerms->get(n))->getResources()->getValue(r))
2994           {
2995             return static_cast <CVTerm *>(mCVTerms->get(n))->getModelQualifierType();
2996           }
2997         }
2998       }
2999     }
3000   }
3001 
3002   return BQM_UNKNOWN;
3003 }
3004 
3005 
3006 /*
3007  * @return the parent Model of this SBML object.
3008  */
3009 const Model*
getModel() const3010 SBase::getModel () const
3011 {
3012   return (mSBML != NULL) ? mSBML->getModel() : NULL;
3013 }
3014 
3015 
3016 /*
3017  * @return the SBML level of this SBML object.
3018  */
3019 unsigned int
getLevel() const3020 SBase::getLevel () const
3021 {
3022   if (mSBML != NULL)
3023     return mSBML->mLevel;
3024   else if (mSBMLNamespaces != NULL)
3025     return mSBMLNamespaces->getLevel();
3026   else
3027     return SBMLDocument::getDefaultLevel();
3028 }
3029 
3030 
3031 /*
3032  * @return the SBML version of this SBML object.
3033  */
3034 unsigned int
getVersion() const3035 SBase::getVersion () const
3036 {
3037   if (mSBML != NULL)
3038     return mSBML->mVersion;
3039   else if (mSBMLNamespaces != NULL)
3040     return mSBMLNamespaces->getVersion();
3041   else
3042     return SBMLDocument::getDefaultVersion();
3043 }
3044 
3045 /*
3046  * @return the SBML version of this SBML object.
3047  */
3048 unsigned int
getPackageCoreVersion() const3049 SBase::getPackageCoreVersion() const
3050 {
3051   const SBMLExtension* sbmlext = SBMLExtensionRegistry::getInstance().getExtensionInternal(mURI);
3052 
3053   if (sbmlext)
3054   {
3055     return sbmlext->getVersion(mURI);
3056   }
3057   return 1;
3058 }
3059 
3060 // ------------------------------------------------------------------
3061   //
3062   //  functions to faciliate matlab binding
3063 
3064 /** @cond doxygenLibsbmlInternal */
3065 int
getAttribute(const std::string & attributeName,double & value) const3066 SBase::getAttribute(const std::string& attributeName, double& value) const
3067 {
3068   return LIBSBML_OPERATION_FAILED;
3069 }
3070 /** @endcond */
3071 
3072 
3073 /** @cond doxygenLibsbmlInternal */
3074 int
getAttribute(const std::string & attributeName,bool & value) const3075 SBase::getAttribute(const std::string& attributeName, bool& value) const
3076 {
3077   return LIBSBML_OPERATION_FAILED;
3078 }
3079 /** @endcond */
3080 
3081 
3082 /** @cond doxygenLibsbmlInternal */
3083 int
getAttribute(const std::string & attributeName,int & value) const3084 SBase::getAttribute(const std::string& attributeName, int& value) const
3085 {
3086   if (attributeName == "sboTerm")
3087   {
3088     value = getSBOTerm();
3089     return LIBSBML_OPERATION_SUCCESS;
3090   }
3091   return LIBSBML_OPERATION_FAILED;
3092 }
3093 /** @endcond */
3094 
3095 
3096 /** @cond doxygenLibsbmlInternal */
3097 int
getAttribute(const std::string & attributeName,unsigned int & value) const3098 SBase::getAttribute(const std::string& attributeName, unsigned int& value) const
3099 {
3100   return LIBSBML_OPERATION_FAILED;
3101 }
3102 /** @endcond */
3103 
3104 
3105 /** @cond doxygenLibsbmlInternal */
3106 int
getAttribute(const std::string & attributeName,std::string & value) const3107 SBase::getAttribute(const std::string& attributeName, std::string& value) const
3108 {
3109   if (attributeName == "metaid")
3110   {
3111     value = getMetaId();
3112     return LIBSBML_OPERATION_SUCCESS;
3113   }
3114   else if (attributeName == "id")
3115   {
3116     value = getIdAttribute();
3117     return LIBSBML_OPERATION_SUCCESS;
3118   }
3119   else if (attributeName == "name")
3120   {
3121     value = getName();
3122     return LIBSBML_OPERATION_SUCCESS;
3123   }
3124   else if (attributeName == "sboTerm")
3125   {
3126     value = getSBOTermID();
3127     return LIBSBML_OPERATION_SUCCESS;
3128   }
3129 
3130 
3131   return LIBSBML_OPERATION_FAILED;
3132 }
3133 /** @endcond */
3134 
3135 
3136 /** @cond doxygenLibsbmlInternal */
3137 //int
3138 //SBase::getAttribute(const std::string& attributeName, const char * value) const
3139 //{
3140 //  if (attributeName == "metaid")
3141 //  {
3142 //    value = getMetaId().c_str();
3143 //    return LIBSBML_OPERATION_SUCCESS;
3144 //  }
3145 //  else if (attributeName == "id")
3146 //  {
3147 //    value = getIdAttribute().c_str();
3148 //    return LIBSBML_OPERATION_SUCCESS;
3149 //  }
3150 //  else if (attributeName == "name")
3151 //  {
3152 //    value = getName().c_str();
3153 //    return LIBSBML_OPERATION_SUCCESS;
3154 //  }
3155 //  else if (attributeName == "sboTerm")
3156 //  {
3157 //    value = getSBOTermID().c_str();
3158 //    return LIBSBML_OPERATION_SUCCESS;
3159 //  }
3160 //
3161 //
3162 //  return LIBSBML_OPERATION_FAILED;
3163 //}
3164 /** @endcond */
3165 
3166 
3167 /** @cond doxygenLibsbmlInternal */
3168 bool
isSetAttribute(const std::string & attributeName) const3169 SBase::isSetAttribute(const std::string& attributeName) const
3170 {
3171   bool value = false;
3172   if (attributeName == "metaid")
3173   {
3174     value = isSetMetaId();
3175   }
3176   else if (attributeName == "id")
3177   {
3178     value = isSetIdAttribute();
3179   }
3180   else if (attributeName == "name")
3181   {
3182     value = isSetName();
3183   }
3184   else if (attributeName == "sboTerm")
3185   {
3186     value = isSetSBOTerm();
3187   }
3188 
3189 
3190   return value;
3191 }
3192 /** @endcond */
3193 
3194 
3195 /** @cond doxygenLibsbmlInternal */
3196 int
setAttribute(const std::string & attributeName,double value)3197 SBase::setAttribute(const std::string& attributeName, double value)
3198 {
3199   return LIBSBML_OPERATION_FAILED;
3200 }
3201 /** @endcond */
3202 
3203 
3204 /** @cond doxygenLibsbmlInternal */
3205 int
setAttribute(const std::string & attributeName,bool value)3206 SBase::setAttribute(const std::string& attributeName, bool value)
3207 {
3208   return LIBSBML_OPERATION_FAILED;
3209 }
3210 /** @endcond */
3211 
3212 
3213 /** @cond doxygenLibsbmlInternal */
3214 int
setAttribute(const std::string & attributeName,int value)3215 SBase::setAttribute(const std::string& attributeName, int value)
3216 {
3217   int return_value = LIBSBML_OPERATION_FAILED;
3218 
3219   if (attributeName == "sboTerm")
3220   {
3221     return_value = setSBOTerm(value);
3222   }
3223 
3224   return return_value;
3225 }
3226 /** @endcond */
3227 
3228 
3229 /** @cond doxygenLibsbmlInternal */
3230 int
setAttribute(const std::string & attributeName,unsigned int value)3231 SBase::setAttribute(const std::string& attributeName, unsigned int value)
3232 {
3233   return LIBSBML_OPERATION_FAILED;
3234 }
3235 /** @endcond */
3236 
3237 
3238 /** @cond doxygenLibsbmlInternal */
3239 int
setAttribute(const std::string & attributeName,const std::string & value)3240 SBase::setAttribute(const std::string& attributeName, const std::string& value)
3241 {
3242   int return_value = LIBSBML_OPERATION_FAILED;
3243   if (attributeName == "metaid")
3244   {
3245     return_value = setMetaId(value);
3246   }
3247   else if (attributeName == "id")
3248   {
3249     return_value = setIdAttribute(value);
3250   }
3251   else if (attributeName == "name")
3252   {
3253     return_value = setName(value);
3254   }
3255   else if (attributeName == "sboTerm")
3256   {
3257     return_value = setSBOTerm(value);
3258   }
3259 
3260 
3261   return return_value;
3262 }
3263 /** @endcond */
3264 
3265 
3266 /** @cond doxygenLibsbmlInternal */
3267 //int
3268 //SBase::setAttribute(const std::string& attributeName, const char * value)
3269 //{
3270 //  int return_value = LIBSBML_OPERATION_FAILED;
3271 //  if (attributeName == "metaid")
3272 //  {
3273 //    return_value = setMetaId(value);
3274 //  }
3275 //  else if (attributeName == "id")
3276 //  {
3277 //    return_value = setIdAttribute(value);
3278 //  }
3279 //  else if (attributeName == "name")
3280 //  {
3281 //    return_value = setName(value);
3282 //  }
3283 //  else if (attributeName == "sboTerm")
3284 //  {
3285 //    return_value = setSBOTerm(value);
3286 //  }
3287 //
3288 //  return return_value;
3289 //}
3290 /** @endcond */
3291 
3292 
3293 /** @cond doxygenLibsbmlInternal */
3294 int
unsetAttribute(const std::string & attributeName)3295 SBase::unsetAttribute(const std::string& attributeName)
3296 {
3297   int value = LIBSBML_OPERATION_FAILED;
3298   if (attributeName == "metaid")
3299   {
3300     value = unsetMetaId();
3301   }
3302   else if (attributeName == "id")
3303   {
3304     value = unsetIdAttribute();
3305   }
3306   else if (attributeName == "name")
3307   {
3308     value = unsetName();
3309   }
3310   else if (attributeName == "sboTerm")
3311   {
3312     value = unsetSBOTerm();
3313   }
3314 
3315 
3316   return value;
3317 }
3318 /** @endcond */
3319 
3320 /** @cond doxygenLibsbmlInternal */
3321 SBase*
createChildObject(const std::string & elementName)3322 SBase::createChildObject(const std::string& elementName)
3323 {
3324   return NULL;
3325 }
3326 /** @endcond */
3327 
3328 /** @cond doxygenLibsbmlInternal */
3329 int
addChildObject(const std::string & elementName,const SBase * element)3330 SBase::addChildObject(const std::string& elementName, const SBase* element)
3331 {
3332   return LIBSBML_OPERATION_FAILED;
3333 }
3334 /** @endcond */
3335 
3336 /** @cond doxygenLibsbmlInternal */
3337 SBase*
removeChildObject(const std::string & elementName,const std::string & id)3338 SBase::removeChildObject(const std::string& elementName, const std::string& id)
3339 {
3340   return NULL;
3341 }
3342 /** @endcond */
3343 
3344 /** @cond doxygenLibsbmlInternal */
3345 
3346 unsigned int
getNumObjects(const std::string & objectName)3347   SBase::getNumObjects(const std::string& objectName)
3348 {
3349   return 0;
3350 }
3351 
3352   /** @endcond */
3353 
3354   /** @cond doxygenLibsbmlInternal */
3355 
3356 SBase*
getObject(const std::string & objectName,unsigned int index)3357 SBase::getObject(const std::string& objectName, unsigned int index)
3358 {
3359   return NULL;
3360 }
3361 
3362   /** @endcond */
3363      /** @cond doxygenLibsbmlInternal */
3364 
3365 int
setMath(const ASTNode * math)3366 SBase::setMath(const ASTNode* math)
3367 {
3368   return LIBSBML_UNEXPECTED_ATTRIBUTE;
3369 }
3370 
3371 int
setMessage(const std::string & message,bool addXHTMLMarkup)3372 SBase::setMessage (const std::string& message, bool addXHTMLMarkup)
3373 {
3374   return LIBSBML_UNEXPECTED_ATTRIBUTE;
3375 }
3376 
3377 std::string
getMessageString() const3378 SBase::getMessageString () const
3379 {
3380   return mEmptyString;
3381 }
3382 
3383 
3384 const ASTNode*
getMath() const3385 SBase::getMath() const
3386 {
3387   return NULL;
3388 }
3389 
3390 
3391 bool
isSetMath() const3392 SBase::isSetMath() const
3393 {
3394   return getMath() != NULL;
3395 }
3396 
3397 
3398 /** @endcond */
3399 
3400 /*
3401  * @return the version of package to which this SBML object
3402  * belongs to.
3403  * 0 will be returned if this element belongs to Core package.
3404  *
3405  * @see getLevel()
3406  * @see getVersion()
3407  */
3408 unsigned int
getPackageVersion() const3409 SBase::getPackageVersion () const
3410 {
3411   const SBMLExtension* sbmlext = SBMLExtensionRegistry::getInstance().getExtensionInternal(mURI);
3412 
3413   if (sbmlext)
3414   {
3415     return sbmlext->getPackageVersion(mURI);
3416   }
3417 
3418   return 0;
3419 }
3420 
3421 
3422 /*
3423  * Returns the name of package in which this element is defined.
3424  *
3425  */
3426 const std::string&
getPackageName() const3427 SBase::getPackageName () const
3428 {
3429   if (SBMLNamespaces::isSBMLNamespace(mURI))
3430   {
3431     static const std::string pkgName = "core";
3432     return pkgName;
3433   }
3434 
3435   const SBMLExtension* sbmlext = SBMLExtensionRegistry::getInstance().getExtensionInternal(mURI);
3436 
3437   if (sbmlext)
3438   {
3439     return sbmlext->getName();
3440   }
3441 
3442   static const std::string pkgName = "unknown";
3443   return pkgName;
3444 }
3445 
3446 
3447 /*
3448  * @return the typecode (int) of this SBML object.
3449  */
3450 int
getTypeCode() const3451 SBase::getTypeCode () const
3452 {
3453   return SBML_UNKNOWN;
3454 }
3455 
3456 
3457 const std::string&
getElementName() const3458 SBase::getElementName () const
3459 {
3460   static const std::string name = "unknown";
3461   return name;
3462 }
3463 
3464 //
3465 //
3466 // (EXTENSION)
3467 //
3468 //
3469 
3470 
3471 /*
3472  * Returns a plugin object (extenstion interface) of package extension
3473  * with the given package name or URI.
3474  *
3475  * @param package the name or URI of the package.
3476  *
3477  * @return the plugin object of package extension with the given package
3478  * name or URI.
3479  */
3480 SBasePlugin*
getPlugin(const std::string & package)3481 SBase::getPlugin(const std::string& package)
3482 {
3483   SBasePlugin* sbPlugin = 0;
3484 
3485   for (size_t i=0; i < mPlugins.size(); i++)
3486   {
3487     std::string uri = mPlugins[i]->getURI();
3488     const SBMLExtension* sbext = SBMLExtensionRegistry::getInstance().getExtensionInternal(uri);
3489     if (uri == package)
3490     {
3491       sbPlugin = mPlugins[i];
3492       break;
3493     }
3494     else if (sbext && (sbext->getName() == package) )
3495     {
3496       sbPlugin = mPlugins[i];
3497       break;
3498     }
3499   }
3500 
3501   return sbPlugin;
3502 }
3503 
3504 
3505 /*
3506  * Returns a plugin object (extenstion interface) of package extension
3507  * with the given package name or URI.
3508  *
3509  * @param package the name or URI of the package.
3510  *
3511  * @return the plugin object of package extension with the given package
3512  * name or URI.
3513  */
3514 const SBasePlugin*
getPlugin(const std::string & package) const3515 SBase::getPlugin(const std::string& package) const
3516 {
3517   return const_cast<SBase*>(this)->getPlugin(package);
3518 }
3519 
3520 
3521 SBasePlugin*
getPlugin(unsigned int n)3522 SBase::getPlugin(unsigned int n)
3523 {
3524   if (n>=getNumPlugins()) return NULL;
3525   return mPlugins[n];
3526 }
3527 
3528 
3529 SBasePlugin*
getDisabledPlugin(unsigned int n)3530 SBase::getDisabledPlugin(unsigned int n)
3531 {
3532   if (n>=getNumDisabledPlugins()) return NULL;
3533   return mDisabledPlugins[n];
3534 }
3535 
3536 
3537 /*
3538  * Returns a plugin object (extenstion interface) of package extension
3539  * with the given package name or URI.
3540  *
3541  * @param package the name or URI of the package.
3542  *
3543  * @return the plugin object of package extension with the given package
3544  * name or URI.
3545  */
3546 const SBasePlugin*
getPlugin(unsigned int n) const3547 SBase::getPlugin(unsigned int n) const
3548 {
3549   return const_cast<SBase*>(this)->getPlugin(n);
3550 }
3551 
3552 
3553 const SBasePlugin*
getDisabledPlugin(unsigned int n) const3554 SBase::getDisabledPlugin(unsigned int n) const
3555 {
3556   return const_cast<SBase*>(this)->getDisabledPlugin(n);
3557 }
3558 
3559 
3560 /*
3561  * Returns the number of plugin objects of package extensions.
3562  *
3563  * @return the number of plugin objects of package extensions.
3564  */
3565 unsigned int
getNumPlugins() const3566 SBase::getNumPlugins() const
3567 {
3568   return (unsigned int)mPlugins.size();
3569 }
3570 
3571 unsigned int
getNumDisabledPlugins() const3572 SBase::getNumDisabledPlugins() const
3573 {
3574   return (unsigned int)mDisabledPlugins.size();
3575 }
3576 
3577 void
deleteDisabledPlugins(bool recursive)3578 SBase::deleteDisabledPlugins(bool recursive /*= true*/)
3579 {
3580   for_each(mDisabledPlugins.begin(), mDisabledPlugins.end(), DeletePluginEntity());
3581   mDisabledPlugins.clear();
3582 
3583   if (recursive)
3584   {
3585     List* list = getAllElements();
3586     for (ListIterator iter = list->begin(); iter != list->end(); ++iter)
3587     {
3588       (static_cast<SBase*>(*iter))->deleteDisabledPlugins();
3589     }
3590     delete list;
3591   }
3592 
3593 }
3594 
3595 int
disablePackage(const std::string & pkgURI,const std::string & prefix)3596 SBase::disablePackage(const std::string& pkgURI, const std::string& prefix)
3597 {
3598   return enablePackage(pkgURI, prefix, false);
3599 }
3600 
3601 /*
3602  * Enables/Disables the given package with this object.
3603  */
3604 int
enablePackage(const std::string & pkgURI,const std::string & prefix,bool flag)3605 SBase::enablePackage(const std::string& pkgURI, const std::string& prefix, bool flag)
3606 {
3607   //
3608   // Checks if the package with the given URI is already enabled/disabled with
3609   // this element.
3610   //
3611   int success = LIBSBML_OPERATION_SUCCESS;
3612 
3613   if (flag)
3614   {
3615     if (isPackageURIEnabled(pkgURI))
3616     {
3617       return success;
3618     }
3619     else if (mSBML != NULL && mSBML->isIgnoredPackage(pkgURI) == true)
3620     {
3621       return success;
3622     }
3623   }
3624   else
3625   {
3626     if (!isPackageURIEnabled(pkgURI))
3627     {
3628       if (mSBML == NULL)
3629       {
3630         return success;
3631 
3632       }
3633       else if (mSBML->isIgnoredPackage(pkgURI) == false)
3634       {
3635         return success;
3636       }
3637     }
3638   }
3639 
3640   // if we are dealing with an unknown package it will not be in the register
3641   if (mSBML == NULL
3642     || (mSBML != NULL && mSBML->isIgnoredPackage(pkgURI) == false
3643    && mSBML->isDisabledIgnoredPackage(pkgURI) == false))
3644   {
3645   //
3646   // Checks if the given pkgURI is registered in SBMLExtensionRegistry
3647   //
3648     if (!SBMLExtensionRegistry::getInstance().isRegistered(pkgURI))
3649     {
3650       return LIBSBML_PKG_UNKNOWN;
3651     }
3652 
3653     const SBMLExtension *sbmlext =
3654           SBMLExtensionRegistry::getInstance().getExtensionInternal(pkgURI);
3655 
3656     //
3657     // Checks version conflicts of the given package
3658     //
3659     if (flag && isPackageEnabled(sbmlext->getName()))
3660     {
3661       return LIBSBML_PKG_CONFLICTED_VERSION;
3662     }
3663 
3664     //
3665     // Checks if the SBML Level and Version of the given pkgURI is
3666     // consistent with those of this object.
3667     //
3668     /* if we happen to be using layout in L2 we cannot do the version
3669      * check since the uri has no way of telling which sbml version is being used.
3670      */
3671     if (sbmlext->getName() == "layout" || sbmlext->getName() == "render" )
3672     {
3673       if (sbmlext->getLevel(pkgURI)   != getLevel() )
3674       {
3675         return LIBSBML_PKG_VERSION_MISMATCH;
3676       }
3677     }
3678     // we decided l3v1 packages would work with l3v2 so dont force the version
3679     // to be the same
3680     //else if ( (sbmlext->getLevel(pkgURI)   != getLevel()  ) ||
3681     //     (sbmlext->getVersion(pkgURI) != getVersion())
3682     //   )
3683     else if (sbmlext->getLevel(pkgURI)   != getLevel()  )
3684     {
3685       return LIBSBML_PKG_VERSION_MISMATCH;
3686     }
3687 
3688   }
3689 
3690   SBase* rootElement = getRootElement();
3691   rootElement->enablePackageInternal(pkgURI,prefix,flag);
3692 
3693   return LIBSBML_OPERATION_SUCCESS;
3694 }
3695 
3696 /** @cond doxygenLibsbmlInternal */
3697 /*
3698  * Enables/Disables the given package with this element and child
3699  * elements (if any).
3700  * (This is an internal implementation for enablePackage function)
3701  */
3702 void
enablePackageInternal(const std::string & pkgURI,const std::string & pkgPrefix,bool flag)3703 SBase::enablePackageInternal(const std::string& pkgURI, const std::string& pkgPrefix, bool flag)
3704 {
3705   if (flag)
3706   {
3707     if (mSBMLNamespaces)
3708     {
3709 #if 0
3710       cout << "[DEBUG] SBase::enablePackageInternal() (uri) " <<  pkgURI
3711         << " (prefix) " << pkgPrefix << " (element) " << getElementName() << endl;
3712 #endif
3713       mSBMLNamespaces->addNamespace(pkgURI, pkgPrefix);
3714     }
3715 
3716     //
3717     // go through disabled plugins, and if we have one re-enable that one, rather
3718     // than creating a new one
3719     //
3720 
3721     bool wasDisabled = false;
3722     int numDisabledPlugins = (int)mDisabledPlugins.size();
3723     for (int i = numDisabledPlugins - 1; i >= 0; --i)
3724     {
3725       SBasePlugin *current = mDisabledPlugins[(size_t)i];
3726       std::string uri = current->getURI();
3727       if (pkgURI == uri)
3728       {
3729         mDisabledPlugins.erase(mDisabledPlugins.begin() + i);
3730         current->connectToParent(this);
3731         mPlugins.push_back(current);
3732         wasDisabled = true;
3733       }
3734     }
3735 
3736 
3737     if (!wasDisabled)
3738     {
3739       //
3740       // enable the given package
3741       //
3742       const SBMLExtension* sbmlext = SBMLExtensionRegistry::getInstance().getExtensionInternal(pkgURI);
3743 
3744       if (sbmlext)
3745       {
3746         SBaseExtensionPoint extPoint(getPackageName(), getTypeCode(), getElementName());
3747         const SBasePluginCreatorBase* sbPluginCreator = sbmlext->getSBasePluginCreator(extPoint);
3748         // trully awful hack for the case where we are adding a plugin to a modelDefinition
3749         // since these do not have plugins the plugin creator is NULL
3750         // we have to force it to realise it is also a core model
3751         if (sbPluginCreator == NULL && getPackageName() == "comp" && getElementName() == "modelDefinition")
3752         {
3753           SBaseExtensionPoint coreextPoint("core", SBML_MODEL, "model");
3754           sbPluginCreator = sbmlext->getSBasePluginCreator(coreextPoint);
3755 
3756         }
3757         if (sbPluginCreator)
3758         {
3759           SBasePlugin* entity = sbPluginCreator->createPlugin(pkgURI, pkgPrefix, getNamespaces());
3760           entity->connectToParent(this);
3761           mPlugins.push_back(entity);
3762         }
3763       }
3764 
3765     }
3766     /* check whether we are trying to reenable an unknown package
3767      * that we previously disabled
3768      */
3769     for (int i = 0; i < mAttributesOfUnknownDisabledPkg.getLength();)
3770     {
3771       if (pkgURI == mAttributesOfUnknownDisabledPkg.getURI(i)
3772         && pkgPrefix == mAttributesOfUnknownDisabledPkg.getPrefix(i))
3773       {
3774         mAttributesOfUnknownPkg.add(
3775           mAttributesOfUnknownDisabledPkg.getName(i),
3776           mAttributesOfUnknownDisabledPkg.getValue(i), pkgURI, pkgPrefix);
3777         mAttributesOfUnknownDisabledPkg.remove(i);
3778       }
3779       else {
3780         i++;
3781       }
3782     }
3783     for (unsigned int i = 0; i < mElementsOfUnknownDisabledPkg.getNumChildren();)
3784     {
3785       if (pkgURI == mElementsOfUnknownDisabledPkg.getChild(i).getURI()
3786         && pkgPrefix == mElementsOfUnknownDisabledPkg.getChild(i).getPrefix())
3787       {
3788         mElementsOfUnknownPkg.addChild(mElementsOfUnknownDisabledPkg.getChild(i));
3789         XMLNode* removed = mElementsOfUnknownDisabledPkg.removeChild(i);
3790         delete removed;
3791       }
3792       else {
3793         i++;
3794       }
3795     }
3796   }
3797   else
3798   {
3799     //
3800     // disable the given package
3801     //
3802     int numPlugins = (int)mPlugins.size();
3803     for (int i=numPlugins-1; i >= 0; --i)
3804     {
3805       SBasePlugin *current = mPlugins[(size_t)i];
3806       std::string uri = current->getURI();
3807       if (pkgURI == uri)
3808       {
3809         mPlugins.erase( mPlugins.begin() + i );
3810         mDisabledPlugins.push_back(current);
3811       }
3812     }
3813 
3814     if (mSBMLNamespaces)
3815     {
3816       mSBMLNamespaces->removeNamespace(pkgURI);
3817     }
3818 
3819     /* before we remove the unknown package keep a copy
3820      * in case we try to re-enable it later
3821      */
3822     for (int i = 0; i < mAttributesOfUnknownPkg.getLength();)
3823     {
3824       if (pkgURI == mAttributesOfUnknownPkg.getURI(i)
3825         && pkgPrefix == mAttributesOfUnknownPkg.getPrefix(i))
3826       {
3827         mAttributesOfUnknownDisabledPkg.add(
3828           mAttributesOfUnknownPkg.getName(i),
3829           mAttributesOfUnknownPkg.getValue(i), pkgURI, pkgPrefix);
3830         mAttributesOfUnknownPkg.remove(i);
3831       }
3832       else {
3833         i++;
3834       }
3835     }
3836     for (unsigned int i = 0; i < mElementsOfUnknownPkg.getNumChildren();)
3837     {
3838       if (pkgURI == mElementsOfUnknownPkg.getChild(i).getURI()
3839         && pkgPrefix == mElementsOfUnknownPkg.getChild(i).getPrefix())
3840       {
3841         mElementsOfUnknownDisabledPkg.addChild(mElementsOfUnknownPkg.getChild(i));
3842         XMLNode* removed = mElementsOfUnknownPkg.removeChild(i);
3843         delete removed;
3844       }
3845       else {
3846         i++;
3847       }
3848     }
3849   }
3850 
3851   /* ---------------------------------------------------------
3852    *
3853    * (EXTENSION)
3854    *
3855    * ----------------------------------------------------------
3856    */
3857 
3858   for (size_t i=0; i < mPlugins.size(); i++)
3859   {
3860     mPlugins[i]->enablePackageInternal(pkgURI,pkgPrefix,flag);
3861   }
3862 }
3863 /** @endcond */
3864 
3865 
3866 /*
3867  * Predicate returning @c true if
3868  * the a package with the given URI is enabled with this object.
3869  *
3870  * @param pkgURI the URI of the package.
3871  *
3872  * @return @c true if the given package is enabled with this object,
3873  * @c false otherwise.
3874  */
3875 bool
isPackageURIEnabled(const std::string & pkgURI) const3876 SBase::isPackageURIEnabled(const std::string& pkgURI) const
3877 {
3878   for (size_t i=0; i < mPlugins.size(); i++)
3879   {
3880     if (mPlugins[i]->getURI() == pkgURI)
3881       return true;
3882   }
3883   return false;
3884 }
3885 
3886 
3887 /*
3888  * Predicate returning @c true if
3889  * the a package with the given URI is enabled with this object.
3890  *
3891  * @param pkgURI the URI of the package.
3892  *
3893  * @return @c true if the given package is enabled with this object,
3894  * @c false otherwise.
3895  */
3896 bool
isPkgURIEnabled(const std::string & pkgURI) const3897 SBase::isPkgURIEnabled(const std::string& pkgURI) const
3898 {
3899   return isPackageURIEnabled(pkgURI);
3900 }
3901 
3902 /*
3903  * Predicate returning @c true if
3904  * the given package (don't care the package version) is enabled with
3905  * this object.
3906  *
3907  * @param pkgName the URI of the package.
3908  *
3909  * @return @c true if the given package is enabled with this object,
3910  * @c false otherwise.
3911  */
3912 bool
isPackageEnabled(const std::string & pkgName) const3913 SBase::isPackageEnabled(const std::string& pkgName) const
3914 {
3915   for (size_t i=0; i < mPlugins.size(); i++)
3916   {
3917     if (mPlugins[i]->getPackageName() == pkgName)
3918       return true;
3919   }
3920   return false;
3921 }
3922 
3923 /*
3924  * Predicate returning @c true if
3925  * the given package (don't care the package version) is enabled with
3926  * this object.
3927  *
3928  * @param pkgName the URI of the package.
3929  *
3930  * @return @c true if the given package is enabled with this object,
3931  * @c false otherwise.
3932  */
3933 bool
isPkgEnabled(const std::string & pkgName) const3934 SBase::isPkgEnabled(const std::string& pkgName) const
3935 {
3936   return isPackageEnabled(pkgName);
3937 }
3938 
3939 bool
hasValidLevelVersionNamespaceCombination()3940 SBase::hasValidLevelVersionNamespaceCombination()
3941 {
3942   int typecode = getTypeCode();
3943   XMLNamespaces *xmlns = getNamespaces();
3944 
3945   return hasValidLevelVersionNamespaceCombination(typecode, xmlns);
3946 }
3947 
3948 /** @cond doxygenLibsbmlInternal */
3949 bool
matchesSBMLNamespaces(const SBase * sb)3950 SBase::matchesSBMLNamespaces(const SBase * sb)
3951 {
3952   bool match = matchesCoreSBMLNamespace(sb);
3953 
3954   if (match == true)
3955   {
3956     SBMLNamespaces *sbmlns = getSBMLNamespaces();
3957     SBMLNamespaces *sbmlns_rhs = sb->getSBMLNamespaces();
3958 
3959     if (sbmlns->getNamespaces()->containIdenticalSetNS(
3960       sbmlns_rhs->getNamespaces()) == false)
3961     {
3962       match = false;
3963     }
3964   }
3965 
3966   return match;
3967 }
3968 
3969 bool
matchesSBMLNamespaces(const SBase * sb) const3970 SBase::matchesSBMLNamespaces(const SBase * sb) const
3971 {
3972   bool match = matchesCoreSBMLNamespace(sb);
3973 
3974   if (match == true)
3975   {
3976     SBMLNamespaces *sbmlns = getSBMLNamespaces();
3977     SBMLNamespaces *sbmlns_rhs = sb->getSBMLNamespaces();
3978 
3979     if (sbmlns->getNamespaces()->containIdenticalSetNS(
3980       sbmlns_rhs->getNamespaces()) == false)
3981     {
3982       match = false;
3983     }
3984   }
3985 
3986   return match;
3987 }
3988 
3989 
3990 bool
matchesRequiredSBMLNamespacesForAddition(const SBase * sb)3991 SBase::matchesRequiredSBMLNamespacesForAddition(const SBase * sb)
3992 {
3993   // if core does not match forget it
3994   bool match = matchesCoreSBMLNamespace(sb);
3995 
3996   if (match == true)
3997   {
3998     XMLNamespaces *xmlns = getSBMLNamespaces()->getNamespaces();
3999     XMLNamespaces *xmlns_rhs = sb->getSBMLNamespaces()->getNamespaces();
4000 
4001     // if child has a package it must match the parent
4002     for (int i = 0; i < xmlns_rhs->getNumNamespaces(); i++)
4003     {
4004       // look to see if the beginning f the uri looks like a package uri
4005       // and if there is a second 'version'
4006       std::string uri = xmlns_rhs->getURI(i);
4007       size_t version = uri.find("http://www.sbml.org/sbml/level3/version");
4008       if (version != string::npos)
4009       {
4010         version = uri.find("version", version+33);
4011       }
4012       if (version != string::npos)
4013       {
4014         if (xmlns->containsUri(uri) == false)
4015         {
4016           match = false;
4017         }
4018       }
4019     }
4020   }
4021 
4022   return match;
4023 }
4024 
4025 
4026 bool
matchesRequiredSBMLNamespacesForAddition(const SBase * sb) const4027 SBase::matchesRequiredSBMLNamespacesForAddition(const SBase * sb) const
4028 {
4029   // if core does not match forget it
4030   bool match = matchesCoreSBMLNamespace(sb);
4031 
4032   if (match == true)
4033   {
4034     XMLNamespaces *xmlns = getSBMLNamespaces()->getNamespaces();
4035     XMLNamespaces *xmlns_rhs = sb->getSBMLNamespaces()->getNamespaces();
4036 
4037     // if child has a package it must match the parent
4038     for (int i = 0; i < xmlns_rhs->getNumNamespaces(); i++)
4039     {
4040       // look to see if the beginning f the uri looks like a package uri
4041       // and if there is a second 'version'
4042       std::string uri = xmlns_rhs->getURI(i);
4043       size_t version = uri.find("http://www.sbml.org/sbml/level3/version");
4044       if (version != string::npos)
4045       {
4046         version = uri.find("version", version+33);
4047       }
4048       if (version != string::npos)
4049       {
4050         if (xmlns->containsUri(uri) == false)
4051         {
4052           match = false;
4053         }
4054       }
4055     }
4056   }
4057 
4058   return match;
4059 }
4060 
4061 
4062 bool
matchesCoreSBMLNamespace(const SBase * sb)4063 SBase::matchesCoreSBMLNamespace(const SBase * sb)
4064 {
4065   bool match = false;
4066 
4067   SBMLNamespaces *sbmlns = getSBMLNamespaces();
4068   SBMLNamespaces *sbmlns_rhs = sb->getSBMLNamespaces();
4069 
4070   if (sbmlns->getLevel() != sbmlns_rhs->getLevel())
4071     return match;
4072 
4073   if (sbmlns->getVersion() != sbmlns_rhs->getVersion())
4074     return match;
4075 
4076   std::string coreNs = SBMLNamespaces::getSBMLNamespaceURI(
4077                        sbmlns->getLevel(), sbmlns->getVersion());
4078 
4079   if (sbmlns->getNamespaces()->containsUri(coreNs)
4080     && sbmlns_rhs->getNamespaces()->containsUri(coreNs))
4081   {
4082     match = true;
4083   }
4084 
4085   //if (sbmlns->getNamespaces()->containIdenticalSetNS(sbmlns_rhs->getNamespaces())
4086   //                                     == true)
4087   //{
4088   //  match = true;
4089   //}
4090 
4091   return match;
4092 }
4093 
4094 
4095 bool
matchesCoreSBMLNamespace(const SBase * sb) const4096 SBase::matchesCoreSBMLNamespace(const SBase * sb) const
4097 {
4098   bool match = false;
4099 
4100   SBMLNamespaces *sbmlns = getSBMLNamespaces();
4101   SBMLNamespaces *sbmlns_rhs = sb->getSBMLNamespaces();
4102 
4103   if (sbmlns->getLevel() != sbmlns_rhs->getLevel())
4104     return match;
4105 
4106   if (sbmlns->getVersion() != sbmlns_rhs->getVersion())
4107     return match;
4108 
4109   std::string coreNs = SBMLNamespaces::getSBMLNamespaceURI(
4110                        sbmlns->getLevel(), sbmlns->getVersion());
4111 
4112   if (sbmlns->getNamespaces()->containsUri(coreNs)
4113     && sbmlns_rhs->getNamespaces()->containsUri(coreNs))
4114   {
4115     match = true;
4116   }
4117 
4118   //if (sbmlns->getNamespaces()->containIdenticalSetNS(sbmlns_rhs->getNamespaces())
4119   //                                     == true)
4120   //{
4121   //  match = true;
4122   //}
4123 
4124   return match;
4125 }
4126 
4127 
4128 bool
hasValidLevelVersionNamespaceCombination(int typecode,XMLNamespaces * xmlns)4129 SBase::hasValidLevelVersionNamespaceCombination(int typecode, XMLNamespaces *xmlns)
4130 {
4131 
4132 
4133   //
4134   // (TODO) Currently, the following check code works only for
4135   //        elements in SBML core.
4136   //        This function may need to be extented for other elements
4137   //        defined in each package extension.
4138   //
4139 
4140   bool valid = true;
4141   bool sbmlDeclared = false;
4142   std::string declaredURI("");
4143   unsigned int version = getVersion();
4144 
4145   if (xmlns != NULL)
4146   {
4147     //
4148     // checks defined SBML XMLNamespace
4149     // returns false if different SBML XMLNamespaces
4150     // (e.g. SBML_XMLNS_L2V1 and SBML_XMLNS_L2V3) are defined.
4151     //
4152     int numNS = 0;
4153 
4154     if (xmlns->hasURI(SBML_XMLNS_L3V2))
4155     {
4156       ++numNS;
4157       declaredURI.assign(SBML_XMLNS_L3V2);
4158     }
4159 
4160     if (xmlns->hasURI(SBML_XMLNS_L3V1))
4161     {
4162       ++numNS;
4163       declaredURI.assign(SBML_XMLNS_L3V1);
4164     }
4165 
4166     if (xmlns->hasURI(SBML_XMLNS_L2V5))
4167     {
4168       if (numNS > 0) return false;
4169       ++numNS;
4170       declaredURI.assign(SBML_XMLNS_L2V5);
4171     }
4172 
4173     if (xmlns->hasURI(SBML_XMLNS_L2V4))
4174     {
4175       if (numNS > 0) return false;
4176       ++numNS;
4177       declaredURI.assign(SBML_XMLNS_L2V4);
4178     }
4179 
4180     if (xmlns->hasURI(SBML_XMLNS_L2V3))
4181     {
4182       // checks different SBML XMLNamespaces
4183       if (numNS > 0) return false;
4184       ++numNS;
4185       declaredURI.assign(SBML_XMLNS_L2V3);
4186     }
4187 
4188     if (xmlns->hasURI(SBML_XMLNS_L2V2))
4189     {
4190       // checks different SBML XMLNamespaces
4191       if (numNS > 0) return false;
4192       ++numNS;
4193       declaredURI.assign(SBML_XMLNS_L2V2);
4194     }
4195 
4196     if (xmlns->hasURI(SBML_XMLNS_L2V1))
4197     {
4198       // checks different SBML XMLNamespaces
4199       if (numNS > 0) return false;
4200       ++numNS;
4201       declaredURI.assign(SBML_XMLNS_L2V1);
4202     }
4203 
4204     if (xmlns->hasURI(SBML_XMLNS_L1))
4205     {
4206       // checks different SBML XMLNamespaces
4207       if (numNS > 0) return false;
4208       ++numNS;
4209       declaredURI.assign(SBML_XMLNS_L1);
4210     }
4211 
4212     // checks if the SBML Namespace is explicitly defined.
4213     for (int i=0; i < xmlns->getLength(); i++)
4214     {
4215       if (!declaredURI.empty() &&
4216                       xmlns->getURI(i) == declaredURI)
4217       {
4218         sbmlDeclared = true;
4219         break;
4220       }
4221     }
4222   }
4223 
4224   const std::string& pkgName = getPackageName();
4225 
4226   if (pkgName == "core")
4227   {
4228   // we need to consider whether it should be necessary to declare the sbml namespace.
4229   //if (!sbmlDeclared)
4230   //  return false;
4231 
4232     if (typecode == SBML_UNKNOWN)
4233     {
4234       valid = false;
4235       return valid;
4236     }
4237     switch (getLevel())
4238     {
4239       case 1:
4240         // some components didnt exist in level 1
4241         if ( typecode == SBML_COMPARTMENT_TYPE
4242           || typecode == SBML_CONSTRAINT
4243           || typecode == SBML_EVENT
4244           || typecode == SBML_EVENT_ASSIGNMENT
4245           || typecode == SBML_FUNCTION_DEFINITION
4246           || typecode == SBML_INITIAL_ASSIGNMENT
4247           || typecode == SBML_SPECIES_TYPE
4248           || typecode == SBML_MODIFIER_SPECIES_REFERENCE
4249           || typecode == SBML_TRIGGER
4250           || typecode == SBML_DELAY
4251         || typecode == SBML_STOICHIOMETRY_MATH
4252         || typecode == SBML_PRIORITY
4253         || typecode == SBML_LOCAL_PARAMETER)
4254           valid = false;
4255        switch (version)
4256         {
4257           case 1:
4258           case 2:
4259             // the namespaces contains the sbml namespaces
4260             // check it is the correct ns for the level/version
4261             if (sbmlDeclared)
4262             {
4263               if (declaredURI != string(SBML_XMLNS_L1))
4264               {
4265                 valid = false;
4266               }
4267             }
4268             break;
4269           default:
4270             valid = false;
4271             break;
4272           }
4273         break;
4274       case 2:
4275         if ( typecode == SBML_PRIORITY
4276         || typecode == SBML_LOCAL_PARAMETER)
4277           valid = false;
4278         switch (version)
4279         {
4280           case 1:
4281             // some components didnt exist in l2v1
4282             if ( typecode == SBML_COMPARTMENT_TYPE
4283               || typecode == SBML_CONSTRAINT
4284               || typecode == SBML_INITIAL_ASSIGNMENT
4285               || typecode == SBML_SPECIES_TYPE)
4286               valid = false;
4287             // the namespaces contains the sbml namespaces
4288             // check it is the correct ns for the level/version
4289             if (sbmlDeclared)
4290             {
4291               if (declaredURI != string(SBML_XMLNS_L2V1))
4292               {
4293                 valid = false;
4294               }
4295             }
4296             break;
4297           case 2:
4298             // the namespaces contains the sbml namespaces
4299             // check it is the correct ns for the level/version
4300             if (sbmlDeclared)
4301             {
4302               if (declaredURI != string(SBML_XMLNS_L2V2))
4303               {
4304                 valid = false;
4305               }
4306             }
4307             break;
4308           case 3:
4309             // the namespaces contains the sbml namespaces
4310             // check it is the correct ns for the level/version
4311             if (sbmlDeclared)
4312             {
4313               if (declaredURI != string(SBML_XMLNS_L2V3))
4314               {
4315                 valid = false;
4316               }
4317             }
4318             break;
4319           case 4:
4320             // the namespaces contains the sbml namespaces
4321             // check it is the correct ns for the level/version
4322             if (sbmlDeclared)
4323             {
4324               if (declaredURI != string(SBML_XMLNS_L2V4))
4325               {
4326                 valid = false;
4327               }
4328             }
4329             break;
4330           case 5:
4331             // the namespaces contains the sbml namespaces
4332             // check it is the correct ns for the level/version
4333             if (sbmlDeclared)
4334             {
4335               if (declaredURI != string(SBML_XMLNS_L2V5))
4336               {
4337                 valid = false;
4338               }
4339             }
4340             break;
4341           default:
4342             valid = false;
4343             break;
4344           }
4345         break;
4346       case 3:
4347         // some components no longer exist in level 3
4348         if ( typecode == SBML_COMPARTMENT_TYPE
4349           || typecode == SBML_SPECIES_TYPE
4350           || typecode == SBML_STOICHIOMETRY_MATH)
4351           valid = false;
4352         switch (version)
4353         {
4354           case 1:
4355            // the namespaces contains the sbml namespaces
4356             // check it is the correct ns for the level/version
4357             if (sbmlDeclared)
4358             {
4359               if (declaredURI != string(SBML_XMLNS_L3V1))
4360               {
4361                 valid = false;
4362               }
4363             }
4364             break;
4365           case 2:
4366            // the namespaces contains the sbml namespaces
4367             // check it is the correct ns for the level/version
4368             if (sbmlDeclared)
4369             {
4370               if (declaredURI != string(SBML_XMLNS_L3V2))
4371               {
4372                 valid = false;
4373               }
4374             }
4375             break;
4376           default:
4377             valid = false;
4378             break;
4379         }
4380         break;
4381       default:
4382         valid = false;
4383         break;
4384     }
4385   }
4386 
4387   // if this is an extension namespace, this method will return the wrong answer,
4388   // so instead return true
4389   ISBMLExtensionNamespaces* test = dynamic_cast<ISBMLExtensionNamespaces*> (mSBMLNamespaces);
4390   if (!valid && test != NULL)
4391     return true;
4392 
4393   return valid;
4394 }
4395 
4396 /* sets the SBMLnamespaces - internal use only*/
4397 int
setSBMLNamespaces(SBMLNamespaces * sbmlns)4398 SBase::setSBMLNamespaces(SBMLNamespaces * sbmlns)
4399 {
4400   if (sbmlns == NULL)
4401     return LIBSBML_INVALID_OBJECT;
4402 
4403   SBMLNamespaces* sbmlnsClone = (sbmlns) ? sbmlns->clone() : 0;
4404   setSBMLNamespacesAndOwn(sbmlnsClone);
4405 
4406   return LIBSBML_OPERATION_SUCCESS;
4407 }
4408 
4409 /*
4410  * sets the SBMLnamespaces - only for internal use in the
4411  * constructors of SBase subclasses in extension packages.
4412  */
4413 void
setSBMLNamespacesAndOwn(SBMLNamespaces * sbmlns)4414 SBase::setSBMLNamespacesAndOwn(SBMLNamespaces * sbmlns)
4415 {
4416   delete mSBMLNamespaces;
4417   mSBMLNamespaces = sbmlns;
4418 
4419   if(sbmlns != NULL)
4420     setElementNamespace(sbmlns->getURI());
4421 }
4422 
4423 
4424 /* gets the SBMLnamespaces - internal use only*/
4425 SBMLNamespaces *
getSBMLNamespaces() const4426 SBase::getSBMLNamespaces() const
4427 {
4428   if (mSBML != NULL)
4429     return mSBML->mSBMLNamespaces;
4430 
4431   // initialize SBML namespace if need be
4432   if (mSBMLNamespaces == NULL)
4433     const_cast<SBase*>(this)->mSBMLNamespaces = new SBMLNamespaces();
4434   return mSBMLNamespaces;
4435 }
4436 /** @endcond */
4437 
4438 
4439 
4440 /*
4441  * @return the partial SBML that describes this SBML object.
4442  */
4443 char*
toSBML()4444 SBase::toSBML ()
4445 {
4446   ostringstream    os;
4447   XMLOutputStream  stream(os, "UTF-8", false);
4448 
4449   write(stream);
4450 
4451   return safe_strdup( os.str().c_str() );
4452 }
4453 
4454 
4455 /** @cond doxygenLibsbmlInternal */
4456 /*
4457  * Reads (initializes) this SBML object by reading from XMLInputStream.
4458  */
4459 void
read(XMLInputStream & stream)4460 SBase::read (XMLInputStream& stream)
4461 {
4462   if ( !stream.peek().isStart() ) return;
4463 
4464   const XMLToken  element  = stream.next();
4465   int             position =  0;
4466 
4467   setSBaseFields( element );
4468 
4469   ExpectedAttributes expectedAttributes;
4470   addExpectedAttributes(expectedAttributes);
4471   readAttributes( element.getAttributes(), expectedAttributes );
4472 
4473   /* if we are reading a document pass the
4474    * SBML Namespace information to the input stream object
4475    * thus the MathML reader can find out what level/version
4476    * of SBML it is parsing
4477    */
4478   if (element.getName() == "sbml")
4479   {
4480     stream.setSBMLNamespaces(this->getSBMLNamespaces());
4481     // need to check that any prefix on the sbmlns also occurs on element
4482     // remembering the horrible situation where the sbmlns might be declared
4483     // with more than one prefix
4484     XMLNamespaces * xmlns = this->getSBMLNamespaces()->getNamespaces();
4485     if (xmlns != NULL)
4486     {
4487       int i = xmlns->getIndexByPrefix(element.getPrefix());
4488       if (i < xmlns->getNumNamespaces())
4489       {
4490         bool errorLoggedAlready = false;
4491         bool error = false;
4492         if (i > -1)
4493         {
4494           if (xmlns->getURI(i) != this->getSBMLNamespaces()->getURI())
4495           {
4496             error = true;
4497           }
4498         }
4499         else if ( i == -1)
4500         {
4501           error = true;
4502         }
4503 
4504         /* if there is a mismatch in level/version this will already
4505          * be logged; do not need another error
4506          */
4507         for (unsigned int n = 0; n < this->getErrorLog()->getNumErrors(); n++)
4508         {
4509           unsigned int errorId =
4510                              this->getErrorLog()->getError(n)->getErrorId();
4511           if (errorId == MissingOrInconsistentLevel
4512             || errorId == MissingOrInconsistentVersion
4513             || errorId == InvalidSBMLLevelVersion
4514             || errorId == InvalidNamespaceOnSBML)
4515           {
4516             errorLoggedAlready = true;
4517           }
4518         }
4519 
4520         if (error == true && errorLoggedAlready == false)
4521         {
4522           static ostringstream errMsg;
4523           errMsg.str("");
4524           errMsg << "The prefix for the <sbml> element does not match "
4525             << "the prefix for the SBML namespace.  This means that "
4526             << "the <sbml> element in not in the SBMLNamespace."<< endl;
4527 
4528           logError(InvalidNamespaceOnSBML,
4529                     getLevel(), getVersion(), errMsg.str());
4530         }
4531       }
4532     }
4533 
4534   }
4535   else
4536   {
4537     //
4538     // checks if the given default namespace (if any) is a valid
4539     // SBML namespace
4540     //
4541     checkDefaultNamespace(mSBMLNamespaces->getNamespaces(), element.getName());
4542     if (!element.getPrefix().empty())
4543     {
4544       XMLNamespaces * prefixedNS = new XMLNamespaces();
4545       prefixedNS->add(element.getURI(), element.getPrefix());
4546       checkDefaultNamespace(prefixedNS, element.getName(), element.getPrefix());
4547       delete prefixedNS;
4548     }
4549   }
4550 
4551   if ( element.isEnd() ) return;
4552 
4553   while ( stream.isGood() )
4554   {
4555     if (CallbackRegistry::invokeCallbacks(getSBMLDocument()) != LIBSBML_OPERATION_SUCCESS)
4556     {
4557       if (getErrorLog() != NULL && !getErrorLog()->contains(OperationInterrupted))
4558         logError(OperationInterrupted, getLevel(), getVersion());
4559       break;
4560     }
4561 
4562     // this used to skip the text
4563     //    stream.skipText();
4564     // instead, read text and store in variable
4565     std::string text;
4566     while(stream.isGood() && stream.peek().isText())
4567     {
4568       text += stream.next().getCharacters();
4569     }
4570     setElementText(text);
4571 
4572     const XMLToken& next = stream.peek();
4573 
4574     // Re-check stream.isGood() because stream.peek() could hit something.
4575     if ( !stream.isGood() ) break;
4576 
4577     if ( next.isEndFor(element) )
4578     {
4579       stream.next();
4580       break;
4581     }
4582     else if ( next.isStart() )
4583     {
4584       const std::string nextName = next.getName();
4585 #if 0
4586       cout << "[DEBUG] SBase::read " << nextName << " uri "
4587            << stream.peek().getURI() << endl;
4588 #endif
4589 
4590       SBase * object = NULL;
4591       try
4592       {
4593         object = createObject(stream);
4594       }
4595       catch (const SBMLExtensionException&)
4596       {
4597         object = NULL;
4598       }
4599 
4600       if (!object)
4601       {
4602         object = createExtensionObject(stream);
4603       }
4604 
4605       if (object != NULL)
4606       {
4607         checkOrderAndLogError(object, position);
4608         position = object->getElementPosition();
4609 
4610         object->connectToParent(static_cast <SBase*>(this));
4611 
4612         object->read(stream);
4613 
4614         if ( !stream.isGood() ) break;
4615 
4616         if (object->getPackageName() == "core"
4617             && object->getTypeCode() == SBML_SPECIES_REFERENCE
4618             && object->getLevel() > 1)
4619         {
4620           static_cast <SpeciesReference *> (object)->sortMath();
4621         }
4622         checkListOfPopulated(object);
4623       }
4624       else if ( !( storeUnknownExtElement(stream)
4625                    || readOtherXML(stream)
4626                    || readAnnotation(stream)
4627                    || readNotes(stream) ))
4628       {
4629         logUnknownElement(nextName, getLevel(), getVersion());
4630         stream.skipPastEnd( stream.next() );
4631       }
4632     }
4633     else
4634     {
4635       stream.skipPastEnd( stream.next() );
4636     }
4637   }
4638 }
4639 /** @endcond */
4640 
4641 
4642 void
setElementText(const std::string &)4643 SBase::setElementText(const std::string &)
4644 {
4645 }
4646 
4647 /** @cond doxygenLibsbmlInternal */
4648 /*
4649  * Writes (serializes) this SBML object by writing it to XMLOutputStream.
4650  */
4651 void
write(XMLOutputStream & stream) const4652 SBase::write (XMLOutputStream& stream) const
4653 {
4654 
4655 #if 0
4656   XMLNamespaces *xmlns = getNamespaces();
4657   {
4658     cout << "[DEBUG] SBase::write (element name) " << getElementName()
4659          << " (element ns) " << getElementNamespace();
4660 
4661     if (xmlns)
4662     {
4663       cout << " (xmlns) ";
4664       XMLOutputStream xos(std::cout);
4665       xos << *xmlns;
4666       cout << endl;
4667     }
4668 
4669   }
4670 #endif
4671 
4672   stream.startElement( getElementName(), getPrefix() );
4673 
4674   writeXMLNS     ( stream );
4675   writeAttributes( stream );
4676   writeElements  ( stream );
4677 
4678   stream.endElement( getElementName(), getPrefix() );
4679 
4680 }
4681 /** @endcond */
4682 
4683 
4684 /** @cond doxygenLibsbmlInternal */
4685 /*
4686  * Subclasses should override this method to write out their contained
4687  * SBML objects as XML elements.  Be sure to call your parent's
4688  * implementation of this method as well.
4689  */
4690 void
writeElements(XMLOutputStream & stream) const4691 SBase::writeElements (XMLOutputStream& stream) const
4692 {
4693   if (mNotes != NULL)
4694   {
4695     mNotes->writeToStream(stream);
4696   }
4697 
4698   /*
4699    * NOTE: CVTerms on a model have already been dealt with
4700    */
4701 
4702   const_cast <SBase *> (this)->syncAnnotation();
4703   if (mAnnotation != NULL) stream << *mAnnotation;
4704 }
4705 
4706 void
writeExtensionElements(XMLOutputStream & stream) const4707 SBase::writeExtensionElements (XMLOutputStream& stream) const
4708 {
4709   /* ---------------------------------------------------------
4710    *
4711    * (EXTENSION)
4712    *
4713    * ----------------------------------------------------------
4714    */
4715 
4716   for (size_t i=0; i < mPlugins.size(); i++)
4717   {
4718     mPlugins[i]->writeElements(stream);
4719   }
4720 
4721   //
4722   // writes elements of unkown packages
4723   //
4724   if (getLevel() > 2)
4725   {
4726     stream << mElementsOfUnknownPkg;
4727   }
4728 
4729   /////////////////////////////////////////////////////////////////////////
4730 
4731 }
4732 /** @endcond */
4733 
4734 
4735 /** @cond doxygenLibsbmlInternal */
4736 /*
4737  * Subclasses should override this method to create, store, and then
4738  * return an SBML object corresponding to the next XMLToken in the
4739  * XMLInputStream.
4740  *
4741  * @return the SBML object corresponding to next XMLToken in the
4742  * XMLInputStream or @c NULL if the token was not recognized.
4743  */
4744 SBase*
createObject(XMLInputStream &)4745 SBase::createObject (XMLInputStream&)
4746 {
4747   return NULL;
4748 }
4749 
4750 
4751 SBase*
createExtensionObject(XMLInputStream & stream)4752 SBase::createExtensionObject (XMLInputStream& stream)
4753 {
4754   SBase* object = NULL;
4755 
4756   /* ---------------------------------------------------------
4757    *
4758    * (EXTENSION)
4759    *
4760    * ----------------------------------------------------------
4761    */
4762 
4763   const string& uri  = stream.peek().getURI();
4764   SBasePlugin* sbext = NULL;
4765 
4766   for (size_t i=0; i < mPlugins.size(); i++)
4767   {
4768     if (mPlugins[i]->getURI() == uri)
4769     {
4770       sbext = mPlugins[i];
4771       break;
4772     }
4773   }
4774 
4775   if (sbext)
4776   {
4777 #if 0
4778     std::cout << "[DEBUG] SBase::createExtensionObject " << getElementName()
4779          << " " << uri << std::endl;
4780 #endif
4781     try
4782     {
4783       object = sbext->createObject(stream);
4784     }
4785     catch (const SBMLExtensionException&)
4786     {
4787       object = NULL;
4788     }
4789   }
4790 #if 0
4791   else
4792   {
4793     std::cout << "[DEBUG] SBase::createExtensionObject " << getElementName()
4794               << " " << uri << " is NULL" << std::endl;
4795   }
4796 #endif
4797 
4798   /////////////////////////////////////////////////////////////////////////
4799 
4800   return object;
4801 }
4802 /** @endcond */
4803 
4804 
4805 /** @cond doxygenLibsbmlInternal */
4806 /*
4807  * Subclasses should override this method to read (and store) XHTML,
4808  * MathML, etc. directly from the XMLInputStream.
4809  *
4810  * @return @c true if the subclass read from the stream, false otherwise.
4811  */
4812 bool
readOtherXML(XMLInputStream & stream)4813 SBase::readOtherXML (XMLInputStream& stream)
4814 {
4815   /* ---------------------------------------------------------
4816    *
4817    * (EXTENSION)
4818    *
4819    * ----------------------------------------------------------
4820    */
4821 
4822   bool read = false;
4823 
4824   for (size_t i=0; i < mPlugins.size(); i++)
4825   {
4826     if (mPlugins[i]->readOtherXML(this, stream))
4827       read = true;
4828   }
4829 
4830   return read;
4831 }
4832 /** @endcond */
4833 
4834 
4835 /** @cond doxygenLibsbmlInternal */
4836 /*
4837  * @return @c true if read an <annotation> element from the stream
4838  */
4839 bool
readAnnotation(XMLInputStream & stream)4840 SBase::readAnnotation (XMLInputStream& stream)
4841 {
4842   const string& name = stream.peek().getName();
4843 
4844   unsigned int level = getLevel();
4845 
4846   if (name == "annotation"
4847     || (level == 1 && getVersion() == 1 && name == "annotations"))
4848   {
4849 //    XMLNode* new_annotation = NULL;
4850     // If this is a level 1 document then annotations are not allowed on
4851     // the sbml container
4852     if (level == 1 && getTypeCode() == SBML_DOCUMENT)
4853     {
4854       logError(AnnotationNotesNotAllowedLevel1);
4855     }
4856 
4857 
4858     // If an annotation already exists, log it as an error and replace
4859     // the content of the existing annotation with the new one.
4860 
4861     if (mAnnotation != NULL)
4862     {
4863       string msg = "An SBML <" + getElementName() + "> element ";
4864       switch(getTypeCode()) {
4865       case SBML_INITIAL_ASSIGNMENT:
4866       case SBML_EVENT_ASSIGNMENT:
4867       case SBML_ASSIGNMENT_RULE:
4868       case SBML_RATE_RULE:
4869         //LS DEBUG:  could use other attribute values, or 'isSetActualId'.
4870         break;
4871       default:
4872         if (isSetId()) {
4873           msg += "with id '" + getId() + "' ";
4874         }
4875         break;
4876       }
4877       msg += "has multiple <annotation> children.";
4878       if (getLevel() < 3)
4879       {
4880         logError(NotSchemaConformant, getLevel(), getVersion(),
4881           "Only one <annotation> element is permitted inside a "
4882           "particular containing element.  " + msg);
4883       }
4884       else
4885       {
4886         logError(MultipleAnnotations, getLevel(), getVersion(), msg);
4887       }
4888     }
4889 
4890     delete mAnnotation;
4891     mAnnotation = new XMLNode(stream);
4892     checkAnnotation();
4893     if(mCVTerms != NULL)
4894     {
4895       unsigned int size = mCVTerms->getSize();
4896       while (size--) delete static_cast<CVTerm*>( mCVTerms->remove(0) );
4897       delete mCVTerms;
4898     }
4899     mCVTerms = new List();
4900     /* might have model history on sbase objects */
4901     if (getLevel() > 2 && getTypeCode()!= SBML_MODEL)
4902     {
4903       delete mHistory;
4904       if (RDFAnnotationParser::hasHistoryRDFAnnotation(mAnnotation))
4905       {
4906         mHistory = RDFAnnotationParser::parseRDFAnnotation(mAnnotation,
4907                                                 getMetaId().c_str(), &(stream));
4908         if (mHistory != NULL && mHistory->hasRequiredAttributes() == false)
4909         {
4910           logError(RDFNotCompleteModelHistory, getLevel(), getVersion(),
4911             "An invalid ModelHistory element has been stored.");
4912         }
4913         setModelHistory(mHistory);
4914       }
4915       else
4916       {
4917         mHistory = NULL;
4918       }
4919     }
4920     if (RDFAnnotationParser::hasCVTermRDFAnnotation(mAnnotation))
4921     {
4922       RDFAnnotationParser::parseRDFAnnotation(mAnnotation, mCVTerms,
4923                                               getMetaId().c_str(), &(stream));
4924 
4925       bool hasNestedTerms = false;
4926       // look at cvterms to see if we have a nested term
4927       for (unsigned int cv = 0; cv < mCVTerms->getSize(); cv++)
4928       {
4929         CVTerm * term = (CVTerm *)(mCVTerms->get(cv));
4930         if (term->getNumNestedCVTerms() > 0)
4931         {
4932           hasNestedTerms = true;
4933           /* this essentially tells the code that rewrites the annotation to
4934            * reconstruct the node and should leave out the nested bit
4935            * if it not allowed
4936            */
4937           term->setHasBeenModifiedFlag();
4938         }
4939       }
4940 
4941       if (hasNestedTerms == true)
4942       {
4943         unsigned int version = getVersion();
4944         if (level < 2 ||
4945             (level == 2 && version < 5) ||
4946             (level == 3) )
4947         {
4948           logError(NestedAnnotationNotAllowed, level, version,
4949             "The nested annotation has been stored but will not be written out.");
4950         }
4951       }
4952 
4953     }
4954 
4955     for (size_t i=0; i < mPlugins.size(); i++)
4956     {
4957       mPlugins[i]->parseAnnotation(this, mAnnotation);
4958     }
4959     return true;
4960   }
4961 
4962   return false;
4963 }
4964 /** @endcond */
4965 
4966 
4967 /** @cond doxygenLibsbmlInternal */
4968 /*
4969  * @return @c true if read a <notes> element from the stream
4970  */
4971 bool
readNotes(XMLInputStream & stream)4972 SBase::readNotes (XMLInputStream& stream)
4973 {
4974   const string& name = stream.peek().getName();
4975 
4976   if (name == "notes")
4977   {
4978     // If this is a level 1 document then notes are not allowed on
4979     // the sbml container
4980     if (getLevel() == 1 && getTypeCode() == SBML_DOCUMENT)
4981     {
4982       logError(AnnotationNotesNotAllowedLevel1);
4983     }
4984 
4985     // If a notes element already exists, then it is an error.
4986     // If an annotation element already exists, then the ordering is wrong.
4987     // In either case, replace existing content with the new notes read.
4988 
4989     if (mNotes != NULL)
4990     {
4991       if (getLevel() < 3)
4992       {
4993         logError(NotSchemaConformant, getLevel(), getVersion(),
4994                 "Only one <notes> element is permitted inside a "
4995               "particular containing element.");
4996       }
4997       else
4998       {
4999         logError(OnlyOneNotesElementAllowed, getLevel(), getVersion());
5000       }
5001     }
5002     else if (mAnnotation != NULL)
5003     {
5004       logError(NotSchemaConformant, getLevel(), getVersion(),
5005                "Incorrect ordering of <annotation> and <notes> elements -- "
5006                "<notes> must come before <annotation> due to the way that "
5007                "the XML Schema for SBML is defined.");
5008     }
5009 
5010     delete mNotes;
5011     mNotes = new XMLNode(stream);
5012 
5013     //
5014     // checks if the given default namespace (if any) is a valid
5015     // SBML namespace
5016     //
5017     const XMLNamespaces &xmlns = mNotes->getNamespaces();
5018     checkDefaultNamespace(&xmlns,"notes");
5019 
5020     if (getSBMLDocument() != NULL)
5021     {
5022       if (getSBMLDocument()->getNumErrors() == 0)
5023       {
5024         checkXHTML(mNotes);
5025       }
5026     }
5027     return true;
5028   }
5029 
5030   return false;
5031 }
5032 
5033 bool
getHasBeenDeleted() const5034 SBase::getHasBeenDeleted() const
5035 {
5036   return mHasBeenDeleted;
5037 }
5038 /** @endcond */
5039 
5040 
5041 /** @cond doxygenLibsbmlInternal */
5042 /*
5043  * @return the ordinal position of the element with respect to its siblings
5044  * or -1 (default) to indicate the position is not significant.
5045  */
5046 int
getElementPosition() const5047 SBase::getElementPosition () const
5048 {
5049   return -1;
5050 }
5051 /** @endcond */
5052 
5053 
5054 /** @cond doxygenLibsbmlInternal */
5055 SBMLErrorLog*
getErrorLog()5056 SBase::getErrorLog ()
5057 {
5058   return (mSBML != NULL) ? mSBML->getErrorLog() : NULL;
5059 }
5060 /** @endcond */
5061 
5062 
5063 /** @cond doxygenLibsbmlInternal */
5064 /*
5065  * Helper to log a common type of error.
5066  */
5067 void
logUnknownAttribute(const string & attribute,const unsigned int level,const unsigned int version,const string & element,const string prefix)5068 SBase::logUnknownAttribute( const string& attribute,
5069                             const unsigned int level,
5070                             const unsigned int version,
5071                             const string& element,
5072                             const string prefix)
5073 {
5074   ostringstream msg;
5075 
5076   if (getPackageName() != "core")
5077   {
5078     if (prefix.empty() == false)
5079     {
5080       msg << "Attribute '" << attribute << "' is not part of the "
5081           << "definition of an SBML Level " << level
5082           << " Version " << version << " Package "
5083           << getPackageName() << " Version " << getPackageVersion() << " <"
5084           << element << "> element.";
5085       if (mSBML != NULL)
5086       {
5087         getErrorLog()->logError(UnknownPackageAttribute,
5088               level, version, msg.str(), getLine(), getColumn());
5089       }
5090     }
5091     else
5092     {
5093       msg << "Attribute '" << attribute << "' is not part of the "
5094           << "definition of an SBML Level " << level
5095           << " Version " << version << " Package "
5096           << getPackageName() << " Version " << getPackageVersion() << " <"
5097           << element << "> element.";
5098       if (mSBML != NULL)
5099       {
5100         getErrorLog()->logError(UnknownCoreAttribute,
5101               level, version, msg.str(), getLine(), getColumn());
5102       }
5103     }
5104     return;
5105   }
5106   else
5107   {
5108     msg << "Attribute '" << attribute << "' is not part of the "
5109         << "definition of an SBML Level " << level
5110         << " Version " << version << " <" << element << "> element.";
5111   }
5112   /* Akiya made this note - so it needs checking BUT if it can crash due to no
5113    * SBMLDocument object then it can crash whatever level - so I put the catch outside
5114    */
5115   if (mSBML)
5116   {
5117   //
5118   // (TODO) Needs to be fixed so that error can be added when
5119   // no SBMLDocument attached.
5120   //
5121     if (level < 3)
5122     {
5123 
5124       getErrorLog()->logError(NotSchemaConformant,
5125             level, version, msg.str(), getLine(), getColumn());
5126     }
5127     else
5128     {
5129       if (element == "<listOfFunctionDefinitions>"
5130         || element == "listOfFunctionDefinitions")
5131       {
5132         getErrorLog()->logError(AllowedAttributesOnListOfFuncs, level,
5133           version, msg.str(), getLine(), getColumn());
5134       }
5135       else if (element == "<sbml>" || element == "sbml")
5136       {
5137         getErrorLog()->logError(AllowedAttributesOnSBML, level,
5138           version, msg.str(), getLine(), getColumn());
5139       }
5140       else if (element == "<listOfUnitDefinitions>"
5141         || element == "listOfUnitDefinitions")
5142       {
5143         getErrorLog()->logError(AllowedAttributesOnListOfUnitDefs, level,
5144           version, msg.str(), getLine(), getColumn());
5145       }
5146       else if (element == "<listOfCompartments>"
5147         || element == "listOfCompartments")
5148       {
5149         getErrorLog()->logError(AllowedAttributesOnListOfComps, level,
5150           version, msg.str(), getLine(), getColumn());
5151       }
5152       else if (element == "<listOfSpecies>" || element == "listOfSpecies")
5153       {
5154         getErrorLog()->logError(AllowedAttributesOnListOfSpecies, level,
5155           version, msg.str(), getLine(), getColumn());
5156       }
5157       else if (element == "<listOfParameters>"
5158         || element == "listOfParameters")
5159       {
5160         getErrorLog()->logError(AllowedAttributesOnListOfParams, level,
5161           version, msg.str(), getLine(), getColumn());
5162       }
5163       else if (element == "<listOfInitialAssignments>"
5164         || element == "listOfInitialAssignments")
5165       {
5166         getErrorLog()->logError(AllowedAttributesOnListOfInitAssign, level,
5167           version, msg.str(), getLine(), getColumn());
5168       }
5169       else if (element == "<listOfRules>" || element == "listOfRules")
5170       {
5171         getErrorLog()->logError(AllowedAttributesOnListOfRules, level,
5172           version, msg.str(), getLine(), getColumn());
5173       }
5174       else if (element == "<listOfConstraints>"
5175         || element == "listOfConstraints")
5176       {
5177         getErrorLog()->logError(AllowedAttributesOnListOfConstraints, level,
5178           version, msg.str(), getLine(), getColumn());
5179       }
5180       else if (element == "<listOfReactions>" || element == "listOfReactions")
5181       {
5182         getErrorLog()->logError(AllowedAttributesOnListOfReactions, level,
5183           version, msg.str(), getLine(), getColumn());
5184       }
5185       else if (element == "<listOfEvents>" || element == "listOfEvents")
5186       {
5187         getErrorLog()->logError(AllowedAttributesOnListOfEvents, level,
5188           version, msg.str(), getLine(), getColumn());
5189       }
5190       else if (element == "<model>" || element == "model")
5191       {
5192         getErrorLog()->logError(AllowedAttributesOnModel, level,
5193           version, msg.str(), getLine(), getColumn());
5194       }
5195       else if (element == "<listOfUnits>" || element == "listOfUnits")
5196       {
5197         getErrorLog()->logError(AllowedAttributesOnListOfUnits, level,
5198           version, msg.str(), getLine(), getColumn());
5199       }
5200       else if (element == "<unitDefinition>" || element == "unitDefinition")
5201       {
5202         getErrorLog()->logError(AllowedAttributesOnUnitDefinition, level,
5203           version, msg.str(), getLine(), getColumn());
5204       }
5205       else if (element == "<unit>" || element == "unit")
5206       {
5207         getErrorLog()->logError(AllowedAttributesOnUnit, level,
5208           version, msg.str(), getLine(), getColumn());
5209       }
5210       else if (element == "<functionDefinition>"
5211         || element == "functionDefinition")
5212       {
5213         getErrorLog()->logError(AllowedAttributesOnFunc, level,
5214           version, msg.str(), getLine(), getColumn());
5215       }
5216       else if (element == "<compartment>" || element == "compartment")
5217       {
5218         getErrorLog()->logError(AllowedAttributesOnCompartment, level,
5219           version, msg.str(), getLine(), getColumn());
5220       }
5221       else if (element == "<species>" || element == "species")
5222       {
5223         getErrorLog()->logError(AllowedAttributesOnSpecies, level,
5224           version, msg.str(), getLine(), getColumn());
5225       }
5226       else if (element == "<parameter>" || element == "parameter")
5227       {
5228         getErrorLog()->logError(AllowedAttributesOnParameter, level,
5229           version, msg.str(), getLine(), getColumn());
5230       }
5231       else if (element == "<initialAssignment>"
5232         || element == "initialAssignment")
5233       {
5234         getErrorLog()->logError(AllowedAttributesOnInitialAssign, level,
5235           version, msg.str(), getLine(), getColumn());
5236       }
5237       else if (element == "<assignmentRule>"
5238         || element == "assignmentRule")
5239       {
5240         getErrorLog()->logError(AllowedAttributesOnAssignRule, level,
5241           version, msg.str(), getLine(), getColumn());
5242       }
5243       else if (element == "<rateRule>" || element == "rateRule")
5244       {
5245         getErrorLog()->logError(AllowedAttributesOnRateRule, level,
5246           version, msg.str(), getLine(), getColumn());
5247       }
5248       else if (element == "<algebraicRule>" || element == "algebraicRule")
5249       {
5250         getErrorLog()->logError(AllowedAttributesOnAlgRule, level,
5251           version, msg.str(), getLine(), getColumn());
5252       }
5253       else if (element == "<constraint>" || element == "constraint")
5254       {
5255         getErrorLog()->logError(AllowedAttributesOnConstraint, level,
5256           version, msg.str(), getLine(), getColumn());
5257       }
5258       else if (element == "<reaction>" || element == "reaction")
5259       {
5260         getErrorLog()->logError(AllowedAttributesOnReaction, level,
5261           version, msg.str(), getLine(), getColumn());
5262       }
5263       else if (element == "<listOfReactants>"
5264         || element == "listOfReactants")
5265       {
5266         getErrorLog()->logError(AllowedAttributesOnListOfSpeciesRef, level,
5267           version, msg.str(), getLine(), getColumn());
5268       }
5269       else if (element == "<listOfProducts>"
5270         || element == "listOfProducts")
5271       {
5272         getErrorLog()->logError(AllowedAttributesOnListOfSpeciesRef, level,
5273           version, msg.str(), getLine(), getColumn());
5274       }
5275       else if (element == "<listOfModifiers>"
5276         || element == "listOfModifiers")
5277       {
5278         getErrorLog()->logError(AllowedAttributesOnListOfMods, level,
5279           version, msg.str(), getLine(), getColumn());
5280       }
5281       else if (element == "<speciesReference>"
5282         || element == "speciesReference")
5283       {
5284         getErrorLog()->logError(AllowedAttributesOnSpeciesReference, level,
5285           version, msg.str(), getLine(), getColumn());
5286       }
5287       else if (element == "<modifierSpeciesReference>"
5288         || element == "modifierSpeciesReference")
5289       {
5290         getErrorLog()->logError(AllowedAttributesOnModifier, level,
5291           version, msg.str(), getLine(), getColumn());
5292       }
5293       else if (element == "<listOfLocalParameters>"
5294         || element == "listOfLocalParameters")
5295       {
5296         getErrorLog()->logError(AllowedAttributesOnListOfLocalParam, level,
5297           version, msg.str(), getLine(), getColumn());
5298       }
5299       else if (element == "<kineticLaw>" || element == "kineticLaw")
5300       {
5301         getErrorLog()->logError(AllowedAttributesOnKineticLaw, level,
5302           version, msg.str(), getLine(), getColumn());
5303       }
5304       else if (element == "<localParameter>" || element == "localParameter")
5305       {
5306         getErrorLog()->logError(AllowedAttributesOnLocalParameter, level,
5307           version, msg.str(), getLine(), getColumn());
5308       }
5309       else if (element == "<event>" || element == "event")
5310       {
5311         getErrorLog()->logError(AllowedAttributesOnEvent, level,
5312           version, msg.str(), getLine(), getColumn());
5313       }
5314       else if (element == "<listOfEventAssignments>"
5315         || element == "listOfEventAssignments")
5316       {
5317         getErrorLog()->logError(AllowedAttributesOnListOfEventAssign, level,
5318           version, msg.str(), getLine(), getColumn());
5319       }
5320       else if (element == "<trigger>" || element == "trigger")
5321       {
5322         getErrorLog()->logError(AllowedAttributesOnTrigger, level,
5323           version, msg.str(), getLine(), getColumn());
5324       }
5325       else if (element == "<delay>" || element == "delay")
5326       {
5327         getErrorLog()->logError(AllowedAttributesOnDelay, level,
5328           version, msg.str(), getLine(), getColumn());
5329       }
5330       else if (element == "<eventAssignment>" || element == "eventAssignment")
5331       {
5332         getErrorLog()->logError(AllowedAttributesOnEventAssignment, level,
5333           version, msg.str(), getLine(), getColumn());
5334       }
5335       else if (element == "<priority>" || element == "priority")
5336       {
5337         getErrorLog()->logError(AllowedAttributesOnPriority, level,
5338           version, msg.str(), getLine(), getColumn());
5339       }
5340   }
5341   }
5342 }
5343 /** @endcond */
5344 
5345 
5346 /** @cond doxygenLibsbmlInternal */
5347 /*
5348  * Helper to log a common type of error.
5349  */
5350 void
logUnknownElement(const string & element,const unsigned int level,const unsigned int version)5351 SBase::logUnknownElement( const string& element,
5352         const unsigned int level,
5353         const unsigned int version )
5354 {
5355   bool logged = false;
5356   ostringstream msg;
5357 
5358   if (level > 2 && getTypeCode() == SBML_LIST_OF)
5359   {
5360     int tc = static_cast<ListOf*>(this)->getItemTypeCode();
5361     msg << "Element '" << element << "' is not part of the definition of <"
5362       << this->getElementName() << ">.";
5363     switch (tc)
5364     {
5365     case SBML_UNIT:
5366       getErrorLog()->logError(OnlyUnitsInListOfUnits,
5367                                 level, version, msg.str(),
5368                                 getLine(), getColumn());
5369       logged = true;
5370       break;
5371     case SBML_FUNCTION_DEFINITION:
5372 
5373       getErrorLog()->logError(OnlyFuncDefsInListOfFuncDefs,
5374                                 level, version, msg.str(),
5375                                 getLine(), getColumn());
5376       logged = true;
5377       break;
5378     case SBML_UNIT_DEFINITION:
5379 
5380       getErrorLog()->logError(OnlyUnitDefsInListOfUnitDefs,
5381                                 level, version, msg.str(),
5382                                 getLine(), getColumn());
5383       logged = true;
5384       break;
5385     case SBML_COMPARTMENT:
5386 
5387       getErrorLog()->logError(OnlyCompartmentsInListOfCompartments,
5388                                 level, version, msg.str(),
5389                                 getLine(), getColumn());
5390       logged = true;
5391       break;
5392     case SBML_SPECIES:
5393 
5394       getErrorLog()->logError(OnlySpeciesInListOfSpecies,
5395                                 level, version, msg.str(),
5396                                 getLine(), getColumn());
5397       logged = true;
5398       break;
5399     case SBML_PARAMETER:
5400 
5401       getErrorLog()->logError(OnlyParametersInListOfParameters,
5402                                 level, version, msg.str(),
5403                                 getLine(), getColumn());
5404       logged = true;
5405       break;
5406     case SBML_INITIAL_ASSIGNMENT:
5407 
5408       getErrorLog()->logError(OnlyInitAssignsInListOfInitAssigns,
5409                                 level, version, msg.str(),
5410                                 getLine(), getColumn());
5411       logged = true;
5412       break;
5413     case SBML_CONSTRAINT:
5414 
5415       getErrorLog()->logError(OnlyConstraintsInListOfConstraints,
5416                                 level, version, msg.str(),
5417                                 getLine(), getColumn());
5418       logged = true;
5419       break;
5420     case SBML_RULE:
5421 
5422       getErrorLog()->logError(OnlyRulesInListOfRules,
5423                                 level, version, msg.str(),
5424                                 getLine(), getColumn());
5425       logged = true;
5426       break;
5427     case SBML_REACTION:
5428 
5429       getErrorLog()->logError(OnlyReactionsInListOfReactions,
5430                                 level, version, msg.str(),
5431                                 getLine(), getColumn());
5432       logged = true;
5433       break;
5434     case SBML_EVENT:
5435 
5436       getErrorLog()->logError(OnlyEventsInListOfEvents,
5437                                 level, version, msg.str(),
5438                                 getLine(), getColumn());
5439       logged = true;
5440       break;
5441     case SBML_LOCAL_PARAMETER:
5442 
5443       getErrorLog()->logError(OnlyLocalParamsInListOfLocalParams,
5444                                 level, version, msg.str(),
5445                                 getLine(), getColumn());
5446       logged = true;
5447       break;
5448     case SBML_EVENT_ASSIGNMENT:
5449 
5450       getErrorLog()->logError(OnlyEventAssignInListOfEventAssign,
5451                                 level, version, msg.str(),
5452                                 getLine(), getColumn());
5453       logged = true;
5454       break;
5455     }
5456   }
5457 
5458   if (logged == false && getPackageName() != "core")
5459   {
5460     // put in a package message
5461     // for now - want to log error from package but needs further work
5462     ostringstream msg1;
5463     msg1 << "Element '" << element << "' is not part of the definition of '"
5464         << this->getElementName() << "' in "
5465         << "SBML Level " << level << " Version " << version
5466         << " Package " << getPackageName()
5467         << " Version " << getPackageVersion() << ".";
5468 
5469     if (mSBML != NULL)
5470     {
5471       getErrorLog()->logError(UnrecognizedElement,
5472           level, version, msg1.str(), getLine(), getColumn());
5473       logged = true;
5474     }
5475   }
5476 
5477   if (logged == false)
5478   {
5479     ostringstream msg1;
5480     msg1 << "Element '" << element << "' is not part of the definition of "
5481         << "SBML Level " << level << " Version " << version << ".";
5482 
5483     if (mSBML != NULL)
5484     {
5485       getErrorLog()->logError(UnrecognizedElement,
5486             level, version, msg1.str(), getLine(), getColumn());
5487     }
5488   }
5489 
5490 }
5491 /** @endcond */
5492 
5493 
5494 /** @cond doxygenLibsbmlInternal */
5495 /*
5496  * Helper to log a common type of error.
5497  */
5498 void
logEmptyString(const string & attribute,const unsigned int level,const unsigned int version,const string & element)5499 SBase::logEmptyString( const string& attribute,
5500                        const unsigned int level,
5501                        const unsigned int version,
5502                        const string& element )
5503 
5504 {
5505   ostringstream msg;
5506 
5507   msg << "Attribute '" << attribute << "' on an "
5508     << element << " must not be an empty string.";
5509 
5510   //
5511   // (TODO) Needs to be fixed so that error can be added when
5512   // no SBMLDocument attached.
5513   //
5514   if (mSBML != NULL)
5515     getErrorLog()->logError(NotSchemaConformant,
5516                             level, version, msg.str(), getLine(), getColumn());
5517 }
5518 /** @endcond */
5519 
5520 
5521 /** @cond doxygenLibsbmlInternal */
5522 /*
5523  * Convenience method for easily logging problems from within method
5524  * implementations.
5525  *
5526  * This is essentially a short form of getErrorLog()->logError(...)
5527  */
5528 void
logError(unsigned int id,const unsigned int,const unsigned int,const std::string details)5529 SBase::logError (  unsigned int       id
5530                  , const unsigned int
5531                  , const unsigned int
5532                  , const std::string details )
5533 {
5534   //
5535   // (TODO) Needs to be fixed so that error can be added when
5536   // no SBMLDocument attached.
5537   //
5538   if ( SBase::getErrorLog() != NULL && mSBML != NULL)
5539     getErrorLog()->logError(id, getLevel(), getVersion(), details, getLine(), getColumn());
5540 }
5541 /** @endcond */
5542 
5543 
5544 /** @cond doxygenLibsbmlInternal */
5545 /**
5546  * Subclasses should override this method to get the list of
5547  * expected attributes.
5548  * This function is invoked from corresponding readAttributes()
5549  * function.
5550  */
5551 void
addExpectedAttributes(ExpectedAttributes & attributes)5552 SBase::addExpectedAttributes(ExpectedAttributes& attributes)
5553 {
5554   //
5555   // metaid: ID { use="optional" }  (L2v1 ->)
5556   //
5557   if (getLevel() > 1 )
5558     attributes.add("metaid");
5559 
5560   //
5561   // sboTerm: SBOTerm { use="optional" }  (L2v3 ->)
5562   //
5563   if (getLevel() > 2 || (getLevel() == 2 && getVersion() > 2) )
5564     attributes.add("sboTerm");
5565 
5566   // l3v2 added id/name to sbase
5567   if (getLevel() == 3 && getVersion() > 1)
5568   {
5569     attributes.add("id");
5570     attributes.add("name");
5571   }
5572 }
5573 
5574 
5575 /*
5576  * Subclasses should override this method to read values from the given
5577  * XMLAttributes set into their specific fields.  Be sure to call your
5578  * parent's implementation of this method as well.
5579  */
5580 void
readAttributes(const XMLAttributes & attributes,const ExpectedAttributes & expectedAttributes)5581 SBase::readAttributes (const XMLAttributes& attributes,
5582                        const ExpectedAttributes& expectedAttributes)
5583 {
5584   const_cast<XMLAttributes&>(attributes).setErrorLog(getErrorLog());
5585 
5586   const unsigned int level   = getLevel  ();
5587   const unsigned int version = getVersion();
5588 
5589   //
5590   // check that all attributes are expected
5591   //
5592   for (int i = 0; i < attributes.getLength(); i++)
5593   {
5594     std::string name   = attributes.getName(i);
5595     std::string uri    = attributes.getURI(i);
5596     std::string prefix = attributes.getPrefix(i);
5597 
5598     //
5599     // To allow prefixed attribute whose namespace doesn't belong to
5600     // core or extension package.
5601     //
5602     // (e.g. xsi:type attribute in Curve element in layout extension)
5603     //
5604     if (!prefix.empty())
5605     {
5606       if ( expectedAttributes.hasAttribute(prefix + ":" + name) ) continue;
5607     }
5608 
5609 
5610     //
5611     // Checks if there are attributes of unknown package extensions
5612     //
5613     // if we happen to be on the sbml element (document) then
5614     // getPrefix() and mURI have not been set and just return defaults
5615     // thus a prefix does not appear to come from the right place !!!
5616     if (!prefix.empty() && getElementName() == "sbml")
5617     {
5618       if (!expectedAttributes.hasAttribute(name))
5619       {
5620         if (name == "required")
5621         {
5622           //we have an l2 doc with a package declared
5623           for (unsigned int i = 0; i < this->getNumPlugins(); ++i)
5624           {
5625             if (getPlugin(i)->getURI() == uri)
5626             {
5627               enablePackageInternal(uri, prefix, false);
5628             }
5629           }
5630           logError(NotSchemaConformant, getLevel(), getVersion(), "The L3 package '" + prefix +
5631             "' cannot be used in this document.");
5632         }
5633         else
5634         {
5635           logUnknownAttribute(name, level, version, getElementName());
5636         }
5637       }
5638     }
5639     else if (!prefix.empty() && (prefix != getPrefix()) && (uri != mURI) )
5640     {
5641       storeUnknownExtAttribute(getElementName(), attributes, (unsigned int)i);
5642     }
5643     else if (!prefix.empty() && level == 3 && getPackageCoreVersion() > 1 && (name == "id" || name == "name"))
5644     {
5645       logUnknownAttribute(name, level, version, getElementName(), prefix);
5646     }
5647     else if (!expectedAttributes.hasAttribute(name))
5648     {
5649       logUnknownAttribute(name, level, version, getElementName(), prefix);
5650     }
5651   }
5652 
5653   if (level > 1)
5654   {
5655     bool assigned = attributes.readInto("metaid", mMetaId, getErrorLog(), false, getLine(), getColumn());
5656 
5657     if (assigned && mMetaId.empty())
5658     {
5659       logEmptyString("metaid", level, version,
5660                      SBMLTypeCode_toString(getTypeCode(), getPackageName().c_str()));
5661     }
5662 
5663     if (isSetMetaId())
5664     {
5665       if (!SyntaxChecker::isValidXMLID(mMetaId))
5666       {
5667         logError(InvalidMetaidSyntax, getLevel(), getVersion(), "The metaid '" + mMetaId + "' does not conform to the syntax.");
5668       }
5669     }
5670   }
5671 
5672   //
5673   // sboTerm: SBOTerm { use="optional" }  (L2v3 ->)
5674   //
5675   // (NOTE)
5676   //
5677   //  SBO::readTerm() must be invoked for L2V2 object in each
5678   //  readAttributes function in SBase derived class if the sboTerm
5679   //  attribute is required in L2V2.
5680   //
5681   if (level > 2 || ( (level == 2) && (version > 2) ) )
5682   {
5683     mSBOTerm = SBO::readTerm(attributes, this->getErrorLog(), level, version,
5684         getLine(), getColumn());
5685   }
5686 
5687   // for l3v2 a document should only have sbo terms from modelling framework
5688   // this is impossible to catch in the validation framework which does not work
5689   // on a document level - so we will need to catch it here
5690   if (isSetSBOTerm() && getTypeCode() == SBML_DOCUMENT)
5691   {
5692     if (!SBO::isModellingFramework(mSBOTerm))
5693     {
5694       std::string message = SBO::intToString(mSBOTerm);
5695       message += " does not derive from the modelling framework branch.";
5696       this->getErrorLog()->logError(InvalidSBMLElementSBOTerm, level, version,
5697         message, getLine(), getColumn());
5698     }
5699   }
5700 
5701   // for l3v2 and above
5702   // read id and name
5703   if (level == 3 && version > 1)
5704   {
5705     XMLTriple tripleId("id", "", "");
5706 
5707     bool assigned = attributes.readInto(tripleId, mId, getErrorLog(), false,
5708                                          getLine(), getColumn());
5709 
5710     if (assigned && mId.empty())
5711     {
5712       logEmptyString("id", level, version,
5713            SBMLTypeCode_toString(getTypeCode(), getPackageName().c_str()));
5714     }
5715 
5716     if (isSetId())
5717     {
5718       if (!SyntaxChecker::isValidInternalSId(mId)) logError(InvalidIdSyntax);
5719     }
5720 
5721     XMLTriple tripleName("name", "", "");
5722     attributes.readInto(tripleName, mName, getErrorLog(), false,
5723                         getLine(), getColumn());
5724 
5725   }
5726   //
5727   // (EXTENSION)
5728   //
5729   readExtensionAttributes(attributes, &expectedAttributes);
5730 }
5731 
5732 
5733 void
readExtensionAttributes(const XMLAttributes & attributes,const ExpectedAttributes * expectedAttributes)5734 SBase::readExtensionAttributes (const XMLAttributes& attributes, const ExpectedAttributes* expectedAttributes)
5735 {
5736   const_cast<XMLAttributes&>(attributes).setErrorLog(getErrorLog());
5737 
5738   /* ---------------------------------------------------------
5739    *
5740    * (EXTENSION)
5741    *
5742    * ----------------------------------------------------------
5743    */
5744     const ExpectedAttributes* base = expectedAttributes  != NULL ?
5745 expectedAttributes : new ExpectedAttributes();
5746 
5747 
5748   for (size_t i=0; i < mPlugins.size(); i++)
5749   {
5750 #if 0
5751     std::cout << "[DEBUG] SBase::readExtensionAttributes "
5752               << mPlugins[i]->getURI()  << " "
5753               << getElementName() << std::endl;
5754 #endif
5755 
5756     ExpectedAttributes ea(*base);
5757 
5758     mPlugins[i]->addExpectedAttributes(ea);
5759     mPlugins[i]->readAttributes(attributes,ea);
5760   }
5761 
5762   if (expectedAttributes  == NULL )
5763     delete base;
5764 
5765   /////////////////////////////////////////////////////////////////////////
5766 
5767 }
5768 
5769 
5770 /**
5771  * Stores the given attribute to the list of ignored attributes if
5772  * the given attribute belongs to some unknown package.
5773  * Unknown attribute error will be logged if the "required" attribute
5774  * of the package in SBMLDocument element is "true".
5775  */
5776 void
storeUnknownExtAttribute(const std::string & element,const XMLAttributes & xattr,unsigned int index)5777 SBase::storeUnknownExtAttribute(const std::string& element,
5778                                 const XMLAttributes& xattr, unsigned int index)
5779 {
5780   if (!mSBML) return;
5781 
5782   if (element == "sbml" && xattr.getName((int)index) == "required")
5783     return;
5784 
5785   std::string uri = xattr.getURI((int)index);
5786 
5787   //
5788   // Checks if the extension package is enabled.
5789   //
5790   if (!mSBML->isPackageURIEnabled(uri))
5791   {
5792     //
5793     // Checks if the extension package with the uri is unsupporeted
5794     // (ignored)
5795     //
5796     if (mSBML->isIgnoredPackage(uri))
5797     {
5798       std::string name   = xattr.getName((int)index);
5799       std::string prefix = xattr.getPrefix((int)index);
5800       std::string value  = xattr.getValue((int)index);
5801 
5802       mAttributesOfUnknownPkg.add(name,value,uri,prefix);
5803 
5804       /* this is now caught earlier and so can be ignored here
5805       if (mSBML->getPackageRequired(uri))
5806       {
5807         logUnknownAttribute(prefix + ":" + name, getLevel(), getVersion(), element);
5808       }
5809       */
5810     }
5811     else
5812     {
5813       std::string name   = xattr.getName((int)index);
5814       std::string prefix = xattr.getPrefix((int)index);
5815       logUnknownAttribute(prefix + ":" + name, getLevel(), getVersion(), element);
5816     }
5817   }
5818 }
5819 
5820 
5821 bool
storeUnknownExtElement(XMLInputStream & stream)5822 SBase::storeUnknownExtElement(XMLInputStream &stream)
5823 {
5824   string uri = stream.peek().getURI();
5825 
5826   if (SBMLNamespaces::isSBMLNamespace(uri))
5827   {
5828     return false;
5829   }
5830   else if (mSBML != NULL && mSBML->isIgnoredPackage(uri))
5831   {
5832     //
5833     // Checks if the extension package with the uri is unknown
5834     // (ignored)
5835     //
5836     /* do not need to do this now i have logged this as
5837      * a required package that cannot be interpreted
5838 
5839     if (mSBML->getPackageRequired(uri))
5840     {
5841       const string& name   = stream.peek().getName();
5842       string prefix = stream.peek().getPrefix();
5843       if (!prefix.empty()) prefix += ":";
5844       logUnknownElement(prefix + name, getLevel(), getVersion());
5845     }
5846     */
5847 
5848     XMLNode xmlnode(stream);
5849     mElementsOfUnknownPkg.addChild(xmlnode);
5850 
5851     return true;
5852   }
5853 
5854   return false;
5855 }
5856 /** @endcond */
5857 
5858 
5859 /** @cond doxygenLibsbmlInternal */
5860 /*
5861  * Returns the prefix of this element.
5862  */
5863 std::string
getPrefix() const5864 SBase::getPrefix() const
5865 {
5866   std::string prefix = "";
5867 
5868   XMLNamespaces *xmlns = getNamespaces();
5869   string uri = getURI();
5870   if(xmlns && mSBML && !mSBML->isEnabledDefaultNS(uri))
5871   {
5872     prefix = xmlns->getPrefix(uri);
5873 #if 0
5874     std::cout << "[DEBUG] SBase::getPrefix() " << prefix << " URI " << mURI
5875               << " element " << getElementName() << std::endl;
5876 #endif
5877   }
5878 #if 0
5879   else
5880   {
5881     if (!xmlns)
5882     {
5883       std::cout << "[DEBUG] SBase::getPrefix() [NO XMLNS] " << prefix << " URI " << mURI
5884               << " element " << getElementName() << std::endl;
5885     }
5886     if (!mSBML)
5887     {
5888       std::cout << "[DEBUG] SBase::getPrefix() [NO mSBML] " << prefix << " URI " << mURI
5889               << " element " << getElementName() << std::endl;
5890     }
5891 
5892   }
5893 #endif
5894 
5895   return prefix;
5896 }
5897 
5898 
5899 /*
5900  * Returns the prefix of this element.
5901  */
5902 std::string
getSBMLPrefix() const5903 SBase::getSBMLPrefix() const
5904 {
5905   std::string prefix = "";
5906 
5907   XMLNamespaces *xmlns = getNamespaces();
5908   if (xmlns == NULL)
5909     return getPrefix();
5910 
5911   for (int i = 0; i < xmlns->getNumNamespaces(); i++)
5912   {
5913     string uri = xmlns->getURI(i);
5914     if (SBMLNamespaces::isSBMLNamespace(uri))
5915       return xmlns->getPrefix(i);
5916   }
5917 
5918   return getPrefix();
5919 }
5920 
5921 /*
5922  * Returns the root element of this element.
5923  *
5924  * @note The root element may not be an SBMLDocument element. For example,
5925  * this element is the root element if this element doesn't have a parent
5926  * SBML object (i.e. mParentSBMLObject is NULL)
5927  */
5928 SBase*
getRootElement()5929 SBase::getRootElement()
5930 {
5931   if (mSBML)
5932   {
5933     return mSBML;
5934   }
5935   else if (mParentSBMLObject)
5936   {
5937     return mParentSBMLObject->getRootElement();
5938   }
5939   else
5940   {
5941     return this;
5942   }
5943 }
5944 
5945 
5946 /*
5947  * Subclasses should override this method to write their XML attributes
5948  * to the XMLOutputStream.  Be sure to call your parent's implementation
5949  * of this method as well.
5950  */
5951 void
writeAttributes(XMLOutputStream & stream) const5952 SBase::writeAttributes (XMLOutputStream& stream) const
5953 {
5954 //  if (getTypeCode() == SBML_DOCUMENT)
5955 //  {
5956 //    if (this->getNamespaces()) stream << *(this->getNamespaces());
5957 //  }
5958   unsigned int level   = getLevel();
5959   unsigned int version = getVersion();
5960   unsigned int pkgCoreVersion = getPackageCoreVersion();
5961   string sbmlPrefix    = getSBMLPrefix();
5962   if ( level > 1 && !mMetaId.empty() )
5963   {
5964     stream.writeAttribute("metaid", sbmlPrefix, mMetaId);
5965   }
5966 
5967   //
5968   // sboTerm: SBOTerm { use="optional" }  (L2v3 ->)
5969   //
5970   // (NOTE)
5971   //
5972   //  SBO::writeTerm() must be invoked for L2V2 object in each
5973   //  readAttributes function in SBase derived class if the sboTerm
5974   //  attribute is required in L2V2.
5975   //
5976   if (level > 2 || ( (level == 2) && (version > 2) ) )
5977   {
5978     SBO::writeTerm(stream, mSBOTerm, sbmlPrefix);
5979   }
5980 
5981   // only write for l3v2 and above
5982   // but do not write for an l3v1 package
5983   if (level == 3 && version > 1)
5984   {
5985     if (getPackageName().empty() || getPackageName() == "core")
5986     {
5987       stream.writeAttribute("id", mId);
5988       stream.writeAttribute("name", mName);
5989     }
5990     else if (getPackageCoreVersion() > 1)
5991     {
5992       stream.writeAttribute("id", mId);
5993       stream.writeAttribute("name", mName);
5994     }
5995   }
5996 }
5997 
5998 
5999 /*
6000  *
6001  * Subclasses should override this method to write their xmlns attriubutes
6002  * (if any) to the XMLOutputStream.  Be sure to call your parent's implementation
6003  * of this method as well.
6004  *
6005  */
6006 void
writeXMLNS(XMLOutputStream &) const6007 SBase::writeXMLNS (XMLOutputStream&) const
6008 {
6009   // do nothing.
6010 }
6011 
6012 
6013 
6014 void
writeExtensionAttributes(XMLOutputStream & stream) const6015 SBase::writeExtensionAttributes (XMLOutputStream& stream) const
6016 {
6017   /* ---------------------------------------------------------
6018    *
6019    * (EXTENSION)
6020    *
6021    * ----------------------------------------------------------
6022    */
6023 
6024   // debug
6025 #if 0
6026   cout << "[DEBUG] SBase::writeExtensionAttributes() " << getTypeCode() << endl;
6027 #endif
6028 
6029   for (size_t i=0; i < mPlugins.size(); i++)
6030   {
6031 #if 0
6032     cout << "[DEBUG] SBase::writeExtensionAttributes() " << i << endl;
6033 #endif
6034     mPlugins[i]->writeAttributes(stream);
6035   }
6036 
6037   //
6038   // writes attributes of unknown packages
6039   //
6040   for (int i=0; i < mAttributesOfUnknownPkg.getLength(); i++)
6041   {
6042     std::string name   = mAttributesOfUnknownPkg.getName(i);
6043     std::string prefix = mAttributesOfUnknownPkg.getPrefix(i);
6044     std::string value  = mAttributesOfUnknownPkg.getValue(i);
6045     stream.writeAttribute(name, prefix, value);
6046   }
6047 
6048   /////////////////////////////////////////////////////////////////////////
6049 }
6050 /** @endcond */
6051 
6052 
6053 /** @cond doxygenLibsbmlInternal */
6054 
6055 
6056 bool
hasOptionalAttributes() const6057 SBase::hasOptionalAttributes() const
6058 {
6059   bool hasAttributes = false;
6060 
6061   if (isSetMetaId() == true)  hasAttributes = true;
6062   if (isSetSBOTerm() == true) hasAttributes = true;
6063 
6064   if (getLevel() == 3 && getVersion() > 1)
6065   {
6066     if (isSetId() == true)  hasAttributes = true;
6067     if (isSetName() == true) hasAttributes = true;
6068   }
6069 
6070   return hasAttributes;
6071 }
6072 
6073 
6074 /** @endcond */
6075 
6076 
6077 /** @cond doxygenLibsbmlInternal */
6078 
6079 
6080 bool
hasOptionalElements() const6081 SBase::hasOptionalElements() const
6082 {
6083   bool hasElements = false;
6084 
6085   if (isSetNotes() == true)  hasElements = true;
6086   if (isSetAnnotation() == true) hasElements = true;
6087 
6088   return hasElements;
6089 }
6090 
6091 
6092 /** @endcond */
6093 
6094 /** @cond doxygenLibsbmlInternal */
6095 /*
6096  * Synchronizes the annotation of this SBML object.
6097  */
6098 void
syncAnnotation()6099 SBase::syncAnnotation ()
6100 {
6101   // look to see whether an existing history has been altered
6102   if (mHistoryChanged == false)
6103   {
6104     if (getModelHistory() != NULL)
6105     {
6106       if (getModelHistory()->hasBeenModified() == true)
6107       {
6108         mHistoryChanged = true;
6109       }
6110     }
6111   }
6112   // or an existing CVTerm
6113   if (mCVTermsChanged == false)
6114   {
6115     for (unsigned int i = 0; i < getNumCVTerms(); i++)
6116     {
6117       if (getCVTerm(i)->hasBeenModified() == true)
6118       {
6119         mCVTermsChanged = true;
6120         break;
6121       }
6122     }
6123   }
6124 
6125   if (mHistoryChanged == true || mCVTermsChanged == true)
6126   {
6127     reconstructRDFAnnotation();
6128     mHistoryChanged = false;
6129     mCVTermsChanged = false;
6130     if (getModelHistory() != NULL)
6131     {
6132       getModelHistory()->resetModifiedFlags();
6133     }
6134     for (unsigned int i = 0; i < getNumCVTerms(); i++)
6135     {
6136       getCVTerm(i)->resetModifiedFlags();
6137     }
6138   }
6139 
6140   if (mAnnotation == NULL)
6141   {
6142     XMLToken ann_token = XMLToken(XMLTriple("annotation", "", ""),
6143                                       XMLAttributes());
6144     mAnnotation = new XMLNode(ann_token);
6145   }
6146 
6147   // sync annotations of plugins
6148   for (size_t i=0; i < mPlugins.size(); i++)
6149   {
6150     mPlugins[i]->syncAnnotation(this, mAnnotation);
6151   }
6152 
6153   // if annotation still empty delete the annotation
6154   if (mAnnotation != NULL && mAnnotation->getNumChildren() == 0)
6155   {
6156     delete mAnnotation;
6157     mAnnotation = NULL;
6158   }
6159 
6160 }
6161 /** @endcond */
6162 
6163 
6164 /** @cond doxygenLibsbmlInternal */
6165 void
reconstructRDFAnnotation()6166 SBase::reconstructRDFAnnotation()
6167 {
6168   bool hasRDF = false;
6169   bool hasAdditionalRDF = false;
6170 
6171   // determine status of existing annotation before doing anything
6172   if (mAnnotation != NULL)
6173   {
6174     hasRDF = RDFAnnotationParser::hasRDFAnnotation(mAnnotation);
6175     hasAdditionalRDF =
6176       RDFAnnotationParser::hasAdditionalRDFAnnotation(mAnnotation);
6177     if (hasAdditionalRDF == false)
6178     {
6179       // look for bizaare case where a user has added a history annotation
6180       // to an object that does not legally include history in MIRIAM compliant
6181       // RDF - this needs to get written out as additional RDF
6182       if (getLevel() < 3 && getTypeCode() != SBML_MODEL
6183         && RDFAnnotationParser::hasHistoryRDFAnnotation(mAnnotation) == true)
6184       {
6185         hasAdditionalRDF = true;
6186       }
6187     }
6188 
6189     if (getLevel() == 2 && getVersion() < 5)
6190     {
6191     // now look for case where the original has nested annotations
6192     // in a level/version where it is strictly speaking invalid
6193     // preserve this annotation as an additional RDF annotation
6194       bool hasNestedAnnotations = false;
6195 
6196       for (unsigned int i = 0; i < getNumCVTerms(); i++)
6197       {
6198         if (getCVTerm(i)->getNumNestedCVTerms() > 0)
6199         {
6200           hasNestedAnnotations = true;
6201           break;
6202         }
6203       }
6204       if (hasRDF == true && hasNestedAnnotations == true)
6205       {
6206         hasAdditionalRDF = true;
6207         // add a copy of the annotation to the RDF as a second RDF element
6208         XMLNode RDF = mAnnotation->getChild("RDF");
6209         XMLNode * desr = RDF.getChild("Description").clone();
6210         mAnnotation->getChild("RDF").addChild(*desr);
6211         delete desr;
6212       }
6213     }
6214   }
6215 
6216   // look at whether the user has changed the RDF elements
6217   if(mAnnotation != NULL && hasRDF)
6218   {
6219     XMLNode* new_annotation = NULL;
6220     if (mHistoryChanged == true)
6221     {
6222       if (mCVTermsChanged == true)
6223       {
6224         new_annotation =
6225           RDFAnnotationParser::deleteRDFAnnotation(mAnnotation);
6226       }
6227       else
6228       {
6229         new_annotation =
6230           RDFAnnotationParser::deleteRDFHistoryAnnotation(mAnnotation);
6231       }
6232     }
6233     else
6234     {
6235       if (mCVTermsChanged == true)
6236       {
6237         new_annotation =
6238           RDFAnnotationParser::deleteRDFCVTermAnnotation(mAnnotation);
6239       }
6240     }
6241 
6242     if(new_annotation != NULL)
6243     {
6244       *mAnnotation = *new_annotation;
6245       delete new_annotation;
6246     }
6247   }
6248 
6249   /* get the history and cvterm annotations from the element */
6250   XMLNode * history = RDFAnnotationParser::parseOnlyModelHistory(this);
6251 
6252   XMLNode * cvTerms = RDFAnnotationParser::parseCVTerms(this);
6253 
6254   if (history != NULL &&  mHistoryChanged == true && mCVTermsChanged == false)
6255   {
6256     if (cvTerms == NULL)
6257     {
6258       if (mAnnotation == NULL)
6259       {
6260         // if there was no annotation before a user added history/cvterms
6261         mAnnotation = history->clone(); //noannot.xml
6262       }
6263       else
6264       {
6265         if (mAnnotation->isEnd())
6266         {
6267           // if the original annotation had only history when it was removed
6268           // it would have left <annotation/> as the annotation
6269           // need this not to be an end element
6270           mAnnotation->unsetEnd(); // histOnly.xml
6271         }
6272 
6273         if (hasAdditionalRDF)
6274         {
6275           // here the annotation after removing history has an RDF top level
6276           // element - the history needs to go into the RDF as the first
6277           // description element
6278           // <rdf><some-non-miriam-rdf> needs to become
6279           // <rdf><History/><some-non-...
6280           // test file histAddRDF
6281           mAnnotation->getChild("RDF").insertChild(0,
6282             history->getChild("RDF").getChild("Description"));
6283         }
6284         else
6285         {
6286           // here the annotation after removing history has either an
6287           // empty annotation element OR one with other top level annotations
6288           // <annotation/> OR <annotation><someAnnotations/>
6289           // just add the whole history RDF annotation
6290           // test files histOnly + histOther
6291           mAnnotation->addChild(history->getChild("RDF"));
6292         }
6293       }
6294     }
6295     else
6296     {
6297       // here the annotation after removing history has an RDF top level
6298       // element with CVTerms and (possibly)other rdf
6299       // - the history needs to go into the first RDF decsription element
6300       // that already has CVTerms
6301       // <rdf><Description-withCVTerms/><some-non-miriam-rdf> needs to become
6302       // <rdf><Description with ModelHistory and CVTerms/><some-non-...
6303       // NOTE: The History Description element has three children
6304       // creator/created and modified
6305       // test file: histCVAddRDF/histCVOnly/histCVOther
6306       unsigned int noChild
6307         = history->getChild("RDF").getChild("Description").getNumChildren();
6308       if (mAnnotation != NULL)
6309       for (unsigned int i = noChild; i > 0; i--)
6310       {
6311         ((mAnnotation->getChild("RDF")).getChild("Description")).insertChild(
6312           0, history->getChild("RDF").getChild("Description").getChild(i-1));
6313       }
6314     }
6315   }
6316 
6317   if (cvTerms != NULL &&  mCVTermsChanged == true && mHistoryChanged == false)
6318   {
6319     if (history == NULL)
6320     {
6321       if (mAnnotation == NULL)
6322       {
6323         // if there was no annotation before a user added history/cvterms
6324         mAnnotation = cvTerms->clone(); //noannot.xml
6325       }
6326       else
6327       {
6328         if (mAnnotation->isEnd())
6329         {
6330           // if the original annotation had only CVTerms when it was removed
6331           // it would have left <annotation/> as the annotation
6332           // need this not to be an end element
6333           mAnnotation->unsetEnd(); // CVOnly.xml
6334         }
6335 
6336         if (hasAdditionalRDF)
6337         {
6338           // here the annotation after removing cvterms has an RDF top level
6339           // element - the cvterms needs to go into the RDF as the first
6340           // description element
6341           // <rdf><some-non-miriam-rdf> needs to become
6342           // <rdf><cvterms/><some-non-...
6343           // test file histAddRDF
6344           mAnnotation->getChild("RDF").insertChild(0,
6345             cvTerms->getChild("RDF").getChild("Description"));
6346         }
6347         else
6348         {
6349           // here the annotation after removing CVTerms has either an
6350           // empty annotation element OR one with other top level annotations
6351           // <annotation/> OR <annotation><someAnnotations/>
6352           // just add the whole CVTerm RDF annotation
6353           // test files CVOnly + CVOther
6354           mAnnotation->addChild(cvTerms->getChild("RDF"));
6355         }
6356       }
6357     }
6358     else
6359     {
6360       // here the annotation after removing cvterms has an RDF top level
6361       // element with history and (possibly)other rdf
6362       // - the cvterms needs to go into the first RDF decsription element
6363       // that already has history but after it
6364       // <rdf><Description-withHistory/><some-non-miriam-rdf> needs to become
6365       // <rdf><Description with History and CVTerms/><some-non-...
6366       // NOTE: The History Description element has three children
6367       // creator/created and modified
6368       // test file: histCVAddRDF/histCVOnly/histCVOther
6369       unsigned int noChild
6370         = cvTerms->getChild("RDF").getChild("Description").getNumChildren();
6371       if (mAnnotation != NULL)
6372       for (unsigned int i = 0; i < noChild; i++)
6373       {
6374         ((mAnnotation->getChild("RDF")).getChild("Description")).addChild(
6375           cvTerms->getChild("RDF").getChild("Description").getChild(i));
6376       }
6377     }
6378   }
6379 
6380   if (mCVTermsChanged == true && mHistoryChanged == true)
6381   {
6382     if (mAnnotation == NULL)
6383     {
6384       // if there was no annotation before a user changed history/cvterms
6385       // need to catch case where user in fact unset history/cvterms
6386       // test file noannot.xml
6387       if (history != NULL)
6388       {
6389         mAnnotation = history->clone();
6390         if (cvTerms != NULL)
6391         {
6392           unsigned int noChild
6393             = cvTerms->getChild("RDF").getChild("Description").getNumChildren();
6394           for (unsigned int i = 0; i < noChild; i++)
6395           {
6396             ((mAnnotation->getChild("RDF")).getChild("Description")).addChild(
6397               cvTerms->getChild("RDF").getChild("Description").getChild(i));
6398           }
6399         }
6400       }
6401       else
6402       {
6403         if (cvTerms != NULL)
6404         {
6405           mAnnotation = cvTerms->clone();
6406         }
6407       }
6408 
6409     }
6410     else
6411     {
6412       if (mAnnotation->isEnd())
6413       {
6414         // if the original annotation had only the miriam-rdf when it was removed
6415         // it would have left <annotation/> as the annotation
6416         // need this not to be an end element
6417         mAnnotation->unsetEnd();
6418       }
6419 
6420       if (hasAdditionalRDF)
6421       {
6422         // here the annotation after removing miriam-rdf has an RDF top level
6423         // element - the history and cvterms need to go into the RDF as the first
6424         // description element
6425         // <rdf><some-non-miriam-rdf> needs to become
6426         // <rdf><HistoryAndCVTerms/><some-non-...
6427         if (history != NULL)
6428         {
6429           mAnnotation->getChild("RDF").insertChild(0,
6430             history->getChild("RDF").getChild("Description"));
6431           if (cvTerms != NULL)
6432           {
6433             unsigned int noChild
6434               = cvTerms->getChild("RDF").getChild("Description").getNumChildren();
6435             for (unsigned int i = 0; i < noChild; i++)
6436             {
6437               ((mAnnotation->getChild("RDF")).getChild("Description")).addChild(
6438                 cvTerms->getChild("RDF").getChild("Description").getChild(i));
6439             }
6440           }
6441         }
6442         else
6443         {
6444           if (cvTerms != NULL)
6445           {
6446            mAnnotation->getChild("RDF").insertChild(0,
6447             cvTerms->getChild("RDF").getChild("Description"));
6448          }
6449         }
6450       }
6451       else
6452       {
6453         // here the annotation after removing miriam-rdf has either an
6454         // empty annotation element OR one with other top level annotations
6455         // <annotation/> OR <annotation><someAnnotations/>
6456         // just add the whole history and cvterms
6457         if (history != NULL)
6458         {
6459           mAnnotation->addChild(history->getChild("RDF"));
6460           if (cvTerms != NULL)
6461           {
6462             unsigned int noChild
6463               = cvTerms->getChild("RDF").getChild("Description").getNumChildren();
6464             for (unsigned int i = 0; i < noChild; i++)
6465             {
6466               ((mAnnotation->getChild("RDF")).getChild("Description")).addChild(
6467                 cvTerms->getChild("RDF").getChild("Description").getChild(i));
6468             }
6469           }
6470         }
6471         else
6472         {
6473           if (cvTerms != NULL)
6474           {
6475             mAnnotation->addChild(cvTerms->getChild("RDF"));
6476           }
6477         }
6478 
6479       }
6480    }
6481 }
6482 
6483 
6484   if (history != NULL) delete history;
6485   if (cvTerms != NULL) delete cvTerms;
6486 }
6487 /** @endcond */
6488 
6489 
6490 /** @cond doxygenLibsbmlInternal */
6491 /*
6492  * Checks that SBML element has been read in the proper order.  If object
6493  * is not in the expected position, an error is logged.
6494  */
6495 void
checkOrderAndLogError(SBase * object,int expected)6496 SBase::checkOrderAndLogError (SBase* object, int expected)
6497 {
6498   int actual = object->getElementPosition();
6499 
6500   if (actual != -1 && actual < expected)
6501   {
6502     SBMLErrorCode_t error = IncorrectOrderInModel;
6503 
6504     if (object->getPackageName() == "core")
6505     {
6506       if (object->getTypeCode() == SBML_LIST_OF)
6507       {
6508         int tc = static_cast<ListOf*>(object)->getItemTypeCode();
6509         //typecode (int) tc = static_cast<ListOf*>(object)->getItemTypeCode();
6510 
6511         if (tc == SBML_SPECIES_REFERENCE || tc == SBML_MODIFIER_SPECIES_REFERENCE)
6512         {
6513           error = IncorrectOrderInReaction;
6514         }
6515       }
6516       else if (object->getTypeCode() == SBML_TRIGGER)
6517       {
6518         error = IncorrectOrderInEvent;
6519       }
6520 
6521       logError(error, getLevel(), getVersion());
6522     }
6523   }
6524 }
6525 /** @endcond */
6526 
6527 
6528 /** @cond doxygenLibsbmlInternal */
6529 /*
6530   * Checks that an SBML ListOf element has been populated.
6531   * If a listOf element has been declared with no elements,
6532   * an error is logged.
6533   */
6534 void
checkListOfPopulated(SBase * object)6535 SBase::checkListOfPopulated(SBase* object)
6536 {
6537   //
6538   // (TODO) Currently, the following check code works only for
6539   //        elements in SBML core.
6540   //        This function may need to be extented for other elements
6541   //        defined in each package extension.
6542   //
6543   if (object->getPackageName() != "core" &&
6544     object->getTypeCode() == SBML_LIST_OF)
6545   {
6546     // for now log the empty list
6547     if (static_cast <ListOf*> (object)->size() == 0)
6548     {
6549       /* hack to stop an empty listOfFunctionTerms that has
6550        * a defaultTerm object being logged as empty
6551        */
6552       if (object->getPackageName() == "qual" &&
6553         object->getElementName() == "listOfFunctionTerms")
6554       {
6555         // do nothing
6556         // will need to check for defaultTerm but will
6557         // have to pass that to the qual extension
6558       }
6559       else if (object->getPackageName() == "multi" &&
6560   object->getElementName() == "listOfSpeciesFeatures")
6561       {
6562   // do nothing
6563   // will need to check for defaultTerm but will
6564   // have to pass that to the multi extension
6565       }
6566       else if (object->getPackageName() == "render" &&
6567         (object->getElementName() == "listOfRenderInformation" ||
6568           object->getElementName() == "listOfGlobalRenderInformation"))
6569       {
6570         // do nothing
6571         // will need to check for defaultTerm but will
6572         // have to pass that to the qual extension
6573       }
6574       else
6575       {
6576         ostringstream errMsg;
6577         errMsg << object->getElementName() << " cannot be empty.";
6578 
6579         logError(NotSchemaConformant, getLevel(), getVersion(), errMsg.str());
6580       }
6581     }
6582     return;
6583   }
6584 
6585   if (object->getTypeCode() == SBML_LIST_OF)
6586   {
6587     // Check that the list has at least one element.
6588     if (static_cast <ListOf*> (object)->size() == 0)
6589     {
6590       //typecode (int) tc = static_cast<ListOf*>(object)->getItemTypeCode();
6591       int tc = static_cast<ListOf*>(object)->getItemTypeCode();
6592       SBMLErrorCode_t error = EmptyListElement;
6593 
6594       // By default, the error will be the EmptyListElement error, unless
6595       // we have a special case for which SBML has a separate error code.
6596       switch (tc)
6597       {
6598       case SBML_UNIT:
6599         if (object->getLevel() < 3)
6600           error = EmptyListOfUnits;
6601         else
6602           error = EmptyUnitListElement;
6603         break;
6604 
6605       case SBML_SPECIES_REFERENCE:
6606       case SBML_MODIFIER_SPECIES_REFERENCE:
6607         error = EmptyListInReaction;
6608         break;
6609 
6610       case SBML_PARAMETER:
6611         // If listOfParameters is inside a KineticLaw, we have a separate code.
6612         if (this->getTypeCode() == SBML_KINETIC_LAW)
6613         {
6614           error = EmptyListInKineticLaw;
6615         }
6616         break;
6617       case SBML_LOCAL_PARAMETER:
6618         error = EmptyListInKineticLaw;
6619         break;
6620       case SBML_EVENT_ASSIGNMENT:
6621         if (object->getLevel() > 2)
6622           error = MissingEventAssignment;
6623         break;
6624 
6625       default:;
6626       }
6627 
6628       logError(error, getLevel(), getVersion());
6629     }
6630     /*
6631      * If there is a non-empty Parameter list in a kinetic law and we are in L3
6632      * report UnrecognisedElement.
6633      */
6634     else if (this->getTypeCode() == SBML_KINETIC_LAW &&
6635              getLevel()          == 3)
6636     {
6637         int tc = static_cast<ListOf*>(object)->getItemTypeCode();
6638         SBMLErrorCode_t error = UnrecognizedElement;
6639         if (tc == SBML_PARAMETER) {
6640             error = UnrecognizedElement;
6641             std::string msg = "SBML Level 3 replaced the <parameter> ";
6642             msg += "within a <kineticLaw> with <localParameter>.";
6643             logError(error, getLevel(), getVersion(), msg);
6644             }
6645     }
6646   }
6647 
6648   else if (object->getTypeCode() == SBML_KINETIC_LAW)
6649   {
6650     /*
6651      * if nothing has been set in the kineticLaw we assume its is empty
6652      */
6653     if (static_cast <KineticLaw *> (object)->isSetMath()           == 0  &&
6654         static_cast <KineticLaw *> (object)->isSetFormula()        == 0  &&
6655         static_cast <KineticLaw *> (object)->isSetTimeUnits()      == 0  &&
6656         static_cast <KineticLaw *> (object)->isSetSubstanceUnits() == 0  &&
6657         static_cast <KineticLaw *> (object)->isSetSBOTerm()        == 0  &&
6658         static_cast <KineticLaw *> (object)->getNumParameters()    == 0)
6659     {
6660       logError(EmptyListInReaction, getLevel(), getVersion());
6661     }
6662   }
6663 }
6664 /** @endcond */
6665 
6666 
6667 /** @cond doxygenLibsbmlInternal */
6668 /* returns the derived units of the object
6669  * needs to be on SBase so that comp can use it for unit checking
6670  * but may also need to be implemented for other packages
6671  */
6672 UnitDefinition*
getDerivedUnitDefinition()6673 SBase::getDerivedUnitDefinition()
6674 {
6675   return NULL;
6676 }
6677 /** @endcond */
6678 
6679 
6680 /** @cond doxygenLibsbmlInternal */
6681 /* returns the derived units of the object
6682  * needs to be on SBase so that comp can use it for unit checking
6683  * but may also need to be implemented for other packages
6684  */
6685 bool
containsUndeclaredUnits()6686 SBase::containsUndeclaredUnits()
6687 {
6688   return false;
6689 }
6690 /** @endcond */
6691 
6692 
6693 //This assumes that the parent of the object is of the type ListOf.  If this is not the case, it will need to be overridden.
removeFromParentAndDelete()6694 int SBase::removeFromParentAndDelete()
6695 {
6696   SBase* parent = getParentSBMLObject();
6697   if (parent==NULL) return LIBSBML_OPERATION_FAILED;
6698   ListOf* parentList = static_cast<ListOf*>(parent);
6699   if (parentList == NULL) return LIBSBML_OPERATION_FAILED;
6700   for (unsigned int i=0; i<parentList->size(); i++) {
6701     SBase* sibling = parentList->get(i);
6702     if (sibling == this) {
6703       parentList->remove(i);
6704       delete this;
6705       return LIBSBML_OPERATION_SUCCESS;
6706     }
6707   }
6708   return LIBSBML_OPERATION_FAILED;
6709 }
6710 
6711 /** @cond doxygenLibsbmlInternal */
6712 const std::string
checkMathMLNamespace(const XMLToken elem)6713 SBase::checkMathMLNamespace(const XMLToken elem)
6714 {
6715   std::string prefix = "";
6716   unsigned int match = 0;
6717   int n;
6718   if (elem.getNamespaces().getLength() != 0)
6719   {
6720     for (n = 0; n < elem.getNamespaces().getLength(); n++)
6721     {
6722       if (!strcmp(elem.getNamespaces().getURI(n).c_str(),
6723                   "http://www.w3.org/1998/Math/MathML"))
6724       {
6725         match = 1;
6726         break;
6727       }
6728     }
6729   }
6730   if (match == 0)
6731   {
6732     if( mSBML->getNamespaces() != NULL)
6733     /* check for implicit declaration */
6734     {
6735       for (n = 0; n < mSBML->getNamespaces()->getLength(); n++)
6736       {
6737         if (!strcmp(mSBML->getNamespaces()->getURI(n).c_str(),
6738                     "http://www.w3.org/1998/Math/MathML"))
6739         {
6740           match = 1;
6741           prefix = mSBML->getNamespaces()->getPrefix(n);
6742           break;
6743         }
6744       }
6745     }
6746   }
6747   if (match == 0)
6748   {
6749     logError(InvalidMathElement, getLevel(), getVersion(), "The MathML namespace 'http://www.w3.org/1998/Math/MathML' was not found.");
6750   }
6751 
6752   return prefix;
6753 }
6754 /** @endcond */
6755 
6756 
6757 /** @cond doxygenLibsbmlInternal */
6758 void
checkDefaultNamespace(const XMLNamespaces * xmlns,const std::string & elementName,const std::string prefix)6759 SBase::checkDefaultNamespace(const XMLNamespaces* xmlns,
6760                              const std::string& elementName,
6761                              const std::string prefix)
6762 {
6763   //
6764   // checks if the given default namespace (if any) is a valid
6765   // SBML namespace
6766   //
6767   if (xmlns == NULL || xmlns->getLength() == 0)
6768     return;
6769 
6770   const std::string defaultURI = xmlns->getURI(prefix);
6771   if (defaultURI.empty() || mURI == defaultURI)
6772     return;
6773 
6774   // if this element (SBase derived) has notes or annotation elements,
6775   // it is ok for them to be in the SBML namespace!
6776   if ( SBMLNamespaces::isSBMLNamespace(defaultURI)
6777        && !SBMLNamespaces::isSBMLNamespace(mURI)
6778        && (elementName == "notes" || elementName == "annotation"))
6779     return;
6780 
6781   static ostringstream errMsg;
6782   errMsg.str("");
6783   errMsg << "xmlns=\"" << defaultURI << "\" in <" << elementName
6784          << "> element is an invalid namespace." << endl;
6785 
6786   logError(NotSchemaConformant, getLevel(), getVersion(), errMsg.str());
6787 
6788 }
6789 
6790 void
read(XMLNode & node,XMLErrorSeverityOverride_t flag)6791 SBase::read(XMLNode& node, XMLErrorSeverityOverride_t flag /*= LIBSBML_OVERRIDE_DISABLED*/)
6792 {
6793   XMLErrorLog* log = getErrorLog();
6794 
6795   // set override for error messages
6796   XMLErrorSeverityOverride_t old = LIBSBML_OVERRIDE_DISABLED;
6797   if (log != NULL )
6798   {
6799     old = log->getSeverityOverride();
6800     log->setSeverityOverride(flag);
6801   }
6802 
6803   const string content = "<?xml version='1.0' encoding='UTF-8'?>"
6804     + XMLNode::convertXMLNodeToString(&node);
6805   XMLInputStream stream(content.c_str(), false);
6806 
6807   // do the parsing using SBase::read
6808   read(stream);
6809 
6810   // restore logging
6811   if (log != NULL )
6812   {
6813     log->setSeverityOverride(old);
6814   }
6815 
6816 }
6817 
6818 XMLNode*
toXMLNode()6819 SBase::toXMLNode()
6820 {
6821   char* rawsbml = toSBML();
6822   SBMLNamespaces *sbmlns = getSBMLNamespaces();
6823   XMLNamespaces xmlns(*sbmlns->getNamespaces());
6824   // in rare cases the above returns a package element with default namespace, however the
6825   // XMLNamespaces would then assign the actual default namespace, which is in most cases
6826   // the SBML namespace. In that case we adjust the default namespace here
6827   ISBMLExtensionNamespaces *extns = dynamic_cast<ISBMLExtensionNamespaces*>(sbmlns);
6828   if (extns != NULL)
6829   {
6830     xmlns.remove("");
6831     xmlns.add(xmlns.getURI(extns->getPackageName()), "");
6832   }
6833   XMLNode* ret = XMLNode::convertStringToXMLNode(rawsbml, &xmlns);
6834   safe_free(rawsbml);
6835   return ret;
6836 }
6837 
6838 
6839 /*
6840   * Checks the annotation does not declare an sbml namespace.
6841   * If the annotation declares an sbml namespace an error is logged.
6842   */
6843 void
checkAnnotation()6844 SBase::checkAnnotation()
6845 {
6846   unsigned int nNodes = 0;
6847   unsigned int match = 0;
6848   int n = 0;
6849   std::vector<std::string> uri_list;
6850   uri_list.clear();
6851 
6852   if (mAnnotation == NULL) return;
6853 
6854   //
6855   // checks if the given default namespace (if any) is a valid
6856   // SBML namespace
6857   //
6858   const XMLNamespaces &xmlns = mAnnotation->getNamespaces();
6859   checkDefaultNamespace(&xmlns,"annotation");
6860 
6861   while (nNodes < mAnnotation->getNumChildren())
6862   {
6863     XMLNode topLevel = mAnnotation->getChild(nNodes);
6864 
6865     // the top level must be an element (so it should be a start)
6866     if (topLevel.isStart() == false)
6867     {
6868       logError(AnnotationNotElement, getLevel(), getVersion());
6869       nNodes++;
6870       continue;
6871     }
6872     std::string uri = topLevel.getURI();
6873     std::string prefix = topLevel.getPrefix();
6874 
6875 #ifdef USE_LIBXML
6876     // sometimes libxml does not catch an empty ns with a prefix
6877     if (uri.empty() && !prefix.empty())
6878     {
6879       logError(BadXMLPrefix);
6880       nNodes++;
6881       continue;
6882     }
6883 #endif
6884 
6885     // cannot be other toplevel element with this uri
6886     if (!uri.empty())
6887     {
6888       if (find(uri_list.begin(), uri_list.end(), uri)
6889                                                != uri_list.end())
6890       {
6891         string msg = "An SBML <" + getElementName() + "> element ";
6892         switch(getTypeCode()) {
6893         case SBML_INITIAL_ASSIGNMENT:
6894         case SBML_EVENT_ASSIGNMENT:
6895         case SBML_ASSIGNMENT_RULE:
6896         case SBML_RATE_RULE:
6897           //LS DEBUG:  could use other attribute values, or 'isSetActualId'.
6898           break;
6899         default:
6900           if (isSetId()) {
6901             msg += "with id '" + getId() + "' ";
6902           }
6903           break;
6904         }
6905         msg += "has an <annotation> child with multiple children with the same namespace.";
6906         logError(DuplicateAnnotationNamespaces, getLevel(), getVersion(), msg);
6907       }
6908       uri_list.push_back(uri);
6909     }
6910 
6911     match = 0;
6912     n = 0;
6913 
6914     bool implicitNSdecl = false;
6915    // must have a namespace
6916     if (topLevel.getNamespaces().getLength() == 0)
6917     {
6918       // not on actual element - is it explicit ??
6919       if( mSBML->getNamespaces() != NULL)
6920       /* check for implicit declaration */
6921       {
6922         for (n = 0; n < mSBML->getNamespaces()->getLength(); n++)
6923         {
6924           if (!strcmp(mSBML->getNamespaces()->getPrefix(n).c_str(),
6925                         prefix.c_str()))
6926           {
6927             implicitNSdecl = true;
6928             break;
6929           }
6930         }
6931      }
6932 
6933 
6934       if (!implicitNSdecl)
6935       {
6936         logError(MissingAnnotationNamespace);
6937       }
6938     }
6939     // cannot declare sbml namespace
6940     while(!match && n < topLevel.getNamespaces().getLength())
6941     {
6942       match += !strcmp(topLevel.getNamespaces().getURI(n).c_str(),
6943                                           "http://www.sbml.org/sbml/level1");
6944       match += !strcmp(topLevel.getNamespaces().getURI(n).c_str(),
6945                                           "http://www.sbml.org/sbml/level2");
6946       match += !strcmp(topLevel.getNamespaces().getURI(n).c_str(),
6947                                 "http://www.sbml.org/sbml/level2/version2");
6948       match += !strcmp(topLevel.getNamespaces().getURI(n).c_str(),
6949                                 "http://www.sbml.org/sbml/level2/version3");
6950       match += !strcmp(topLevel.getNamespaces().getURI(n).c_str(),
6951                                 "http://www.sbml.org/sbml/level2/version4");
6952       match += !strcmp(topLevel.getNamespaces().getURI(n).c_str(),
6953                                 "http://www.sbml.org/sbml/level2/version5");
6954       match += !strcmp(topLevel.getNamespaces().getURI(n).c_str(),
6955                                 "http://www.sbml.org/sbml/level3/version1/core");
6956       match += !strcmp(topLevel.getNamespaces().getURI(n).c_str(),
6957                                 "http://www.sbml.org/sbml/level3/version2/core");
6958       n++;
6959     }
6960     string msg = "An SBML <" + getElementName() + "> element ";
6961     switch(getTypeCode()) {
6962     case SBML_INITIAL_ASSIGNMENT:
6963     case SBML_EVENT_ASSIGNMENT:
6964     case SBML_ASSIGNMENT_RULE:
6965     case SBML_RATE_RULE:
6966       //LS DEBUG:  could use other attribute values, or 'isSetActualId'.
6967       break;
6968     default:
6969       if (isSetId()) {
6970         msg += "with id '" + getId() + "' ";
6971       }
6972       break;
6973     }
6974     if (match > 0)
6975     {
6976       msg += "uses a restricted namespace on an element in its child <annotation>.";
6977       logError(SBMLNamespaceInAnnotation, getLevel(), getVersion(), msg);
6978       break;
6979     }
6980 
6981     if (implicitNSdecl && prefix.empty())
6982     {
6983       /* if this is L3 a missing namespace with empty prefix means
6984        * it is using the sbml ns - which is allowed in L3
6985        */
6986       if (getLevel() < 3)
6987       {
6988         logError(MissingAnnotationNamespace, getLevel(), getVersion(),
6989           msg + "lacks a namespace declaration on an element in its child <annotation>.");
6990       }
6991       msg += "uses a restricted namespace on an element in its child <annotation>.";
6992       logError(SBMLNamespaceInAnnotation, getLevel(), getVersion(), msg);
6993     }
6994     nNodes++;
6995   }
6996 }
6997 /** @endcond */
6998 
6999 
7000 /** @cond doxygenLibsbmlInternal */
7001 /*
7002  * Checks that the XHTML is valid.
7003  * If the xhtml does not conform to the specification of valid xhtml within
7004  * an sbml document, an error is logged.
7005  */
7006 void
checkXHTML(const XMLNode * xhtml)7007 SBase::checkXHTML(const XMLNode * xhtml)
7008 {
7009   if (xhtml == NULL) return;
7010 
7011   const string&  name = xhtml->getName();
7012   unsigned int i, errorNS, errorXML, errorDOC, errorELEM;
7013 
7014   if (name == "notes")
7015   {
7016     errorNS   = NotesNotInXHTMLNamespace;
7017     errorXML  = NotesContainsXMLDecl;
7018     errorDOC  = NotesContainsDOCTYPE;
7019     errorELEM = InvalidNotesContent;
7020   }
7021   else if (name == "message")
7022   {
7023     errorNS   = ConstraintNotInXHTMLNamespace;
7024     errorXML  = ConstraintContainsXMLDecl;
7025     errorDOC  = ConstraintContainsDOCTYPE;
7026     errorELEM = InvalidConstraintContent;
7027   }
7028   else                                  // We shouldn't ever get to this point.
7029   {
7030     logError(UnknownError);
7031     return;
7032   }
7033 
7034   /*
7035   * errors relating to a misplaced XML or DOCTYPE declaration
7036   * will also cause a parser error.
7037   * since parsing will terminate at this error, then if it has occurred
7038   * it will be in the XML currently being checked and so a more
7039   * informative message can be added
7040   */
7041   for (i = 0; i < getErrorLog()->getNumErrors(); i++)
7042   {
7043     if (getErrorLog()->getError(i)->getErrorId() == BadXMLDeclLocation)
7044     {
7045       logError(errorXML);
7046     }
7047     if (getErrorLog()->getError(i)->getErrorId() == BadlyFormedXML)
7048     {
7049       logError(errorDOC);
7050     }
7051   }
7052 
7053   XMLNamespaces* toplevelNS = (mSBML) ? mSBML->getNamespaces() : NULL;
7054 
7055   /*
7056   * namespace declaration is variable
7057   * if a whole html tag has been used
7058   * or a whole body tag then namespace can be implicitly declared
7059   */
7060   unsigned int children = xhtml->getNumChildren();
7061 
7062   if (children > 1)
7063   {
7064     for (i=0; i < children; i++)
7065     {
7066       if (SyntaxChecker::isAllowedElement(xhtml->getChild(i)))
7067       {
7068         if (!SyntaxChecker::hasDeclaredNS(xhtml->getChild(i),
7069                                                   toplevelNS))
7070         {
7071           logError(errorNS);
7072         }
7073       }
7074       else
7075       {
7076         logError(errorELEM);
7077       }
7078     }
7079   }
7080   else
7081   {
7082     /* only one element which can be html or body with either implicit/explicit
7083     * namespace declaration
7084     * OR could be one of the listed elements.
7085     */
7086 
7087     const string& top_name = xhtml->getChild(0).getName();
7088 
7089     if (top_name != "html" && top_name != "body"
7090       && !SyntaxChecker::isAllowedElement(xhtml->getChild(0)))
7091     {
7092       logError(errorELEM);
7093     }
7094     else
7095     {
7096       if (!SyntaxChecker::hasDeclaredNS(xhtml->getChild(0), toplevelNS))
7097       {
7098         logError(errorNS);
7099       }
7100       if (top_name == "html"
7101         && !SyntaxChecker::isCorrectHTMLNode(xhtml->getChild(0)))
7102       {
7103         logError(errorELEM);
7104       }
7105     }
7106   }
7107 }
7108 /** @endcond */
7109 /** @cond doxygenLibsbmlInternal */
7110 /* default for components that have no required attributes */
7111 bool
hasRequiredAttributes() const7112 SBase::hasRequiredAttributes() const
7113 {
7114   return true;
7115 }
7116 
7117 /* default for components that have no required elements */
7118 bool
hasRequiredElements() const7119 SBase::hasRequiredElements() const
7120 {
7121   return true;
7122 }
7123 
7124 int
checkCompatibility(const SBase * object) const7125 SBase::checkCompatibility(const SBase * object) const
7126 {
7127   if (object == NULL)
7128   {
7129     return LIBSBML_OPERATION_FAILED;
7130   }
7131   else if (!(object->hasRequiredAttributes()) || !(object->hasRequiredElements()))
7132   {
7133     return LIBSBML_INVALID_OBJECT;
7134   }
7135   else if (getLevel() != object->getLevel())
7136   {
7137     return LIBSBML_LEVEL_MISMATCH;
7138   }
7139   else if (getVersion() != object->getVersion())
7140   {
7141     return LIBSBML_VERSION_MISMATCH;
7142   }
7143   else if (this->matchesRequiredSBMLNamespacesForAddition(object) == false)
7144   {
7145     return LIBSBML_NAMESPACES_MISMATCH;
7146   }
7147   else
7148   {
7149     return LIBSBML_OPERATION_SUCCESS;
7150   }
7151 }
7152 
7153 void
removeDuplicateAnnotations()7154 SBase::removeDuplicateAnnotations()
7155 {
7156   bool resetNecessary = false;
7157   XMLNamespaces xmlns = XMLNamespaces();
7158   xmlns.add("http://www.sbml.org/libsbml/annotation", "");
7159   XMLTriple triple = XMLTriple("duplicateTopLevelElements",
7160     "http://www.sbml.org/libsbml/annotation", "");
7161   XMLAttributes att = XMLAttributes();
7162   XMLToken token = XMLToken(triple, att, xmlns);
7163   XMLNode * newNode = NULL;
7164   if (isSetAnnotation())
7165   {
7166     //make a copy to work with
7167     XMLNode * newAnnotation = mAnnotation->clone();
7168 
7169     unsigned int numChildren = newAnnotation->getNumChildren();
7170     if (numChildren == 1)
7171       return;
7172 
7173     bool duplicate = false;
7174     for (unsigned int i = 0; i < numChildren; i++)
7175     {
7176       duplicate = false;
7177       std::string name = newAnnotation->getChild(i).getName();
7178       for (unsigned int j = numChildren-1; j > i; j--)
7179       {
7180         if (name == newAnnotation->getChild(j).getName())
7181         {
7182           resetNecessary = true;
7183           duplicate = true;
7184           if (newNode == NULL)
7185           {
7186             // need to  create the new node
7187             newNode = new XMLNode(token);
7188           }
7189           XMLNode* transfer = newAnnotation->removeChild(j);
7190           newNode->addChild(*transfer);
7191           delete transfer;
7192         }
7193       }
7194       if (duplicate)
7195       {
7196         XMLNode* transfer = newAnnotation->removeChild(i);
7197         newNode->addChild(*transfer);
7198         delete transfer;
7199       }
7200       numChildren = newAnnotation->getNumChildren();
7201     }
7202     if (resetNecessary)
7203     {
7204       newAnnotation->addChild(*(newNode));
7205       setAnnotation(newAnnotation);
7206     }
7207     delete newNode;
7208     delete newAnnotation;
7209   }
7210 
7211 
7212 }
7213 /** @endcond */
7214 
7215 /** @cond doxygenLibsbmlInternal */
7216 /*
7217  * Stores the location (line and column) and any XML namespaces (for
7218  * roundtripping) declared on this SBML (XML) element.
7219  */
7220 void
setSBaseFields(const XMLToken & element)7221 SBase::setSBaseFields (const XMLToken& element)
7222 {
7223   mLine   = element.getLine  ();
7224   mColumn = element.getColumn();
7225 
7226   if (element.getNamespaces().getLength() > 0)
7227   {
7228     XMLNamespaces tmpxmlns(element.getNamespaces());
7229     setNamespaces(&tmpxmlns);
7230   }
7231   else
7232   {
7233     setNamespaces(NULL);
7234   }
7235 }
7236 /** @endcond */
7237 
7238 /** @cond doxygenLibsbmlInternal */
7239 /*
7240  *
7241  * (Extension)
7242  *
7243  * Sets the XML namespace to which this element belogns to.
7244  * For example, all elements that belong to SBML Level 3 Version 1 Core
7245  * must set the namespace to "http://www.sbml.org/sbml/level3/version1/core";
7246  * all elements that belong to Layout Extension Version 1 for SBML Level 3
7247  * Version 1 Core must set the namespace to
7248  * "http://www.sbml.org/sbml/level3/version1/layout/version1/"
7249  *
7250  */
7251 int
setElementNamespace(const std::string & uri)7252 SBase::setElementNamespace(const std::string &uri)
7253 {
7254 //  cout << "[DEBUG] SBase::setElementNamespace() " << uri << endl;
7255   mURI = uri;
7256 
7257   return LIBSBML_OPERATION_SUCCESS;
7258 }
7259 /** @endcond */
7260 
7261 /** @cond doxygenLibsbmlInternal */
7262 void
updateSBMLNamespace(const std::string & package,unsigned int level,unsigned int version)7263 SBase::updateSBMLNamespace(const std::string& package, unsigned int level,
7264   unsigned int version)
7265 {
7266   if (package.empty() || package == "core")
7267   {
7268     std::string uri;
7269 
7270     switch (level)
7271     {
7272     case 1:
7273       uri = SBML_XMLNS_L1;
7274       break;
7275     case 2:
7276       switch (version)
7277       {
7278       case 1:
7279         uri = SBML_XMLNS_L2V1;
7280         break;
7281       case 2:
7282         uri = SBML_XMLNS_L2V2;
7283         break;
7284       case 3:
7285         uri = SBML_XMLNS_L2V3;
7286         break;
7287       case 4:
7288         uri = SBML_XMLNS_L2V4;
7289         break;
7290       case 5:
7291       default:
7292         uri = SBML_XMLNS_L2V5;
7293         break;
7294       }
7295       break;
7296     case 3:
7297     default:
7298       switch (version)
7299       {
7300       case 1:
7301         uri = SBML_XMLNS_L3V1;
7302         break;
7303       case 2:
7304       default:
7305         uri = SBML_XMLNS_L3V2;
7306         break;
7307       }
7308       break;
7309     }
7310     // is there a prefix on the sbml namespace
7311     std::string currentSBMLCoreURI =
7312       SBMLNamespaces::getSBMLNamespaceURI(getLevel(),
7313         getVersion());
7314     std::string currentSBMLCorePrefix = "";
7315 
7316     if (mSBMLNamespaces == NULL)
7317     {
7318       mSBMLNamespaces = new SBMLNamespaces(level, version);
7319     }
7320 
7321 
7322     if (mSBMLNamespaces->getNamespaces() != NULL &&
7323       mSBMLNamespaces->getNamespaces()->getLength() > 0)
7324     {
7325       currentSBMLCorePrefix = mSBMLNamespaces->getNamespaces()->
7326         getPrefix(currentSBMLCoreURI);
7327       mSBMLNamespaces->getNamespaces()->remove(currentSBMLCorePrefix);
7328       mSBMLNamespaces->getNamespaces()->add(uri, currentSBMLCorePrefix);
7329 
7330       // it is possible that the ns exists unprefixed as well as prefixed
7331       // the code will return the first it encounters
7332       // so check if the original ns is still there
7333       if (mSBMLNamespaces->getNamespaces()->containsUri(currentSBMLCoreURI) == true)
7334       {
7335         currentSBMLCorePrefix = mSBMLNamespaces->getNamespaces()
7336           ->getPrefix(currentSBMLCoreURI);
7337         mSBMLNamespaces->getNamespaces()->remove(currentSBMLCorePrefix);
7338         mSBMLNamespaces->getNamespaces()->add(uri, currentSBMLCorePrefix);
7339       }
7340     }
7341     else
7342     {
7343       mSBMLNamespaces->addNamespace(uri, currentSBMLCorePrefix);
7344     }
7345 
7346     mSBMLNamespaces->setLevel(level);
7347     mSBMLNamespaces->setVersion(version);
7348     if (this->getPackageName().empty() || this->getPackageName() == "core")
7349       setElementNamespace(uri);
7350   }
7351   else
7352   {
7353     std::string uri = this->getSBMLNamespaces()->getNamespaces()->getURI(package);
7354     const SBMLExtension* sbmlext = SBMLExtensionRegistry::getInstance().getExtensionInternal(uri);
7355     // so we have a plugin for this package already enabled
7356     // if there are two version 1 of this package
7357     // we want is to change the uri being used
7358     if (sbmlext && sbmlext->isEnabled())
7359     {
7360       std::string newURI;
7361       newURI.assign(uri);
7362       size_t pos = newURI.find("level3");
7363       if (version == 1)
7364       {
7365         newURI.replace(pos, 15, "level3/version1");
7366       }
7367       else if (version == 2)
7368       {
7369         newURI.replace(pos, 15, "level3/version2");
7370       }
7371 
7372       bool found = false;
7373       unsigned int count = 0;
7374       while (!found && count < sbmlext->getNumOfSupportedPackageURI())
7375       {
7376         if (newURI == sbmlext->getSupportedPackageURI(count))
7377         {
7378           found = true;
7379         }
7380         count++;
7381       }
7382 
7383       if (found)
7384       {
7385         mSBMLNamespaces->getNamespaces()->remove(uri);
7386         mSBMLNamespaces->getNamespaces()->add(newURI, package);
7387         if (this->getPackageName() == package)
7388           setElementNamespace(newURI);
7389       }
7390     }
7391 
7392   }
7393 
7394   for (size_t i = 0; i < mPlugins.size(); i++)
7395   {
7396     mPlugins[i]->updateSBMLNamespace(package, level, version);
7397   }
7398 
7399 }
7400 /** @endcond */
7401 
7402 /** @cond doxygenLibsbmlInternal */
7403 /*
7404  * Returns the XML namespace to which this element belongs to.
7405  */
7406 const std::string&
getElementNamespace() const7407 SBase::getElementNamespace() const
7408 {
7409   return mURI;
7410 }
7411 /** @endcond */
7412 
7413 #endif /* __cplusplus */
7414 
7415 /** @cond doxygenIgnored */
7416 LIBSBML_EXTERN
7417 int
SBase_addCVTerm(SBase_t * sb,CVTerm_t * term)7418 SBase_addCVTerm(SBase_t *sb, CVTerm_t *term)
7419 {
7420   return (sb != NULL) ? sb->addCVTerm(term) : LIBSBML_INVALID_OBJECT;
7421 }
7422 
7423 
7424 LIBSBML_EXTERN
7425 int
SBase_addCVTermNewBag(SBase_t * sb,CVTerm_t * term)7426 SBase_addCVTermNewBag(SBase_t *sb, CVTerm_t *term)
7427 {
7428   return (sb != NULL) ? sb->addCVTerm(term, true) : LIBSBML_INVALID_OBJECT;
7429 }
7430 
7431 
7432 LIBSBML_EXTERN
7433 List_t*
SBase_getCVTerms(SBase_t * sb)7434 SBase_getCVTerms(SBase_t *sb)
7435 {
7436   return (sb != NULL) ? sb->getCVTerms() : 0;
7437 }
7438 
7439 
7440 LIBSBML_EXTERN
7441 unsigned int
SBase_getNumCVTerms(SBase_t * sb)7442 SBase_getNumCVTerms(SBase_t *sb)
7443 {
7444   return (sb != NULL) ? sb->getNumCVTerms() : SBML_INT_MAX;
7445 }
7446 
7447 LIBSBML_EXTERN
7448 CVTerm_t*
SBase_getCVTerm(SBase_t * sb,unsigned int n)7449 SBase_getCVTerm(SBase_t *sb, unsigned int n)
7450 {
7451   return (sb != NULL) ? static_cast <CVTerm_t *> (sb->getCVTerm(n)) : NULL;
7452 }
7453 
7454 LIBSBML_EXTERN
7455 int
SBase_unsetCVTerms(SBase_t * sb)7456 SBase_unsetCVTerms(SBase_t *sb)
7457 {
7458   return (sb != NULL) ? sb->unsetCVTerms() : LIBSBML_INVALID_OBJECT;
7459 }
7460 
7461 
7462 LIBSBML_EXTERN
7463 ModelHistory_t *
SBase_getModelHistory(SBase_t * sb)7464 SBase_getModelHistory(SBase_t *sb)
7465 {
7466   return (sb != NULL) ? sb->getModelHistory() : NULL;
7467 }
7468 
7469 LIBSBML_EXTERN
7470 int
SBase_isSetModelHistory(SBase_t * sb)7471 SBase_isSetModelHistory(SBase_t *sb)
7472 {
7473   return (sb != NULL) ? static_cast<int>( sb->isSetModelHistory() ) : 0;
7474 }
7475 
7476 
7477 LIBSBML_EXTERN
7478 int
SBase_setModelHistory(SBase_t * sb,ModelHistory_t * history)7479 SBase_setModelHistory(SBase_t *sb, ModelHistory_t *history)
7480 {
7481   return (sb != NULL) ? sb->setModelHistory(history) : LIBSBML_INVALID_OBJECT;
7482 }
7483 
7484 LIBSBML_EXTERN
7485 int
SBase_unsetModelHistory(SBase_t * sb)7486 SBase_unsetModelHistory(SBase_t *sb)
7487 {
7488   return (sb != NULL) ? sb->unsetModelHistory() : LIBSBML_INVALID_OBJECT;
7489 }
7490 
7491 
7492 LIBSBML_EXTERN
7493 BiolQualifierType_t
SBase_getResourceBiologicalQualifier(SBase_t * sb,const char * resource)7494 SBase_getResourceBiologicalQualifier(SBase_t *sb, const char * resource)
7495 {
7496   if (sb != NULL)
7497     return (resource != NULL) ?
7498     sb->getResourceBiologicalQualifier(resource) : BQB_UNKNOWN;
7499   else
7500     return BQB_UNKNOWN;
7501 }
7502 
7503 
7504 LIBSBML_EXTERN
7505 ModelQualifierType_t
SBase_getResourceModelQualifier(SBase_t * sb,const char * resource)7506 SBase_getResourceModelQualifier(SBase_t *sb, const char * resource)
7507 {
7508   if (sb != NULL)
7509     return (resource != NULL) ?
7510     sb->getResourceModelQualifier(resource) : BQM_UNKNOWN;
7511   else
7512     return BQM_UNKNOWN;
7513 }
7514 
7515 
7516 LIBSBML_EXTERN
7517 const char *
SBase_getMetaId(SBase_t * sb)7518 SBase_getMetaId (SBase_t *sb)
7519 {
7520   return (sb != NULL && sb->isSetMetaId()) ? sb->getMetaId().c_str() : NULL;
7521 }
7522 
7523 
7524 LIBSBML_EXTERN
7525 const char *
SBase_getIdAttribute(SBase_t * sb)7526 SBase_getIdAttribute (SBase_t *sb)
7527 {
7528   return (sb != NULL && sb->isSetIdAttribute()) ? sb->getIdAttribute().c_str() : NULL;
7529 }
7530 
7531 
7532 LIBSBML_EXTERN
7533 const char *
SBase_getName(SBase_t * sb)7534 SBase_getName (SBase_t *sb)
7535 {
7536   return (sb != NULL && sb->isSetName()) ? sb->getName().c_str() : NULL;
7537 }
7538 
7539 
7540 LIBSBML_EXTERN
7541 const SBMLDocument_t *
SBase_getSBMLDocument(SBase_t * sb)7542 SBase_getSBMLDocument (SBase_t *sb)
7543 {
7544   return (sb != NULL) ? sb->getSBMLDocument() : NULL;
7545 }
7546 
7547 
7548 LIBSBML_EXTERN
7549 const SBase_t *
SBase_getParentSBMLObject(SBase_t * sb)7550 SBase_getParentSBMLObject (SBase_t *sb)
7551 {
7552   return (sb != NULL) ? sb->getParentSBMLObject() : NULL;
7553 }
7554 
7555 
7556 LIBSBML_EXTERN
7557 const SBase_t *
SBase_getAncestorOfType(SBase_t * sb,int type,const char * pkgName)7558 SBase_getAncestorOfType (SBase_t *sb, int type, const char* pkgName)
7559 {
7560   return (sb != NULL) ? sb->getAncestorOfType(type, pkgName) : NULL;
7561 }
7562 
7563 
7564 LIBSBML_EXTERN
7565 int
SBase_getSBOTerm(const SBase_t * sb)7566 SBase_getSBOTerm (const SBase_t *sb)
7567 {
7568   return (sb != NULL) ? sb->getSBOTerm() : SBML_INT_MAX;
7569 }
7570 
7571 
7572 LIBSBML_EXTERN
7573 char*
SBase_getSBOTermID(const SBase_t * sb)7574 SBase_getSBOTermID (const SBase_t *sb)
7575 {
7576   return (sb != NULL && sb->isSetSBOTerm())?
7577     safe_strdup(sb->getSBOTermID().c_str()) : NULL;
7578 }
7579 
7580 
7581 LIBSBML_EXTERN
7582 char*
SBase_getSBOTermAsURL(const SBase_t * sb)7583 SBase_getSBOTermAsURL (const SBase_t *sb)
7584 {
7585   return (sb != NULL && sb->isSetSBOTerm())?
7586     safe_strdup(sb->getSBOTermAsURL().c_str()) : NULL;
7587 }
7588 
7589 
7590 LIBSBML_EXTERN
7591 unsigned int
SBase_getLevel(const SBase_t * sb)7592 SBase_getLevel (const SBase_t *sb)
7593 {
7594   return (sb != NULL) ? sb->getLevel() : SBML_INT_MAX;
7595 }
7596 
7597 
7598 LIBSBML_EXTERN
7599 unsigned int
SBase_getVersion(const SBase_t * sb)7600 SBase_getVersion (const SBase_t *sb)
7601 {
7602   return (sb != NULL) ? sb->getVersion() : SBML_INT_MAX;
7603 }
7604 
7605 
7606 LIBSBML_EXTERN
7607 XMLNode_t *
SBase_getNotes(SBase_t * sb)7608 SBase_getNotes (SBase_t *sb)
7609 {
7610   return (sb != NULL) ? sb->getNotes() : NULL;
7611 }
7612 
7613 
7614 LIBSBML_EXTERN
7615 char*
SBase_getNotesString(SBase_t * sb)7616 SBase_getNotesString (SBase_t *sb)
7617 {
7618   return (sb != NULL && sb->isSetNotes()) ?
7619     safe_strdup(sb->getNotesString().c_str()) : NULL;
7620 }
7621 
7622 
7623 LIBSBML_EXTERN
7624 XMLNode_t *
SBase_getAnnotation(SBase_t * sb)7625 SBase_getAnnotation (SBase_t *sb)
7626 {
7627   return (sb != NULL) ? sb->getAnnotation() : NULL;
7628 }
7629 
7630 
7631 LIBSBML_EXTERN
7632 char*
SBase_getAnnotationString(SBase_t * sb)7633 SBase_getAnnotationString (SBase_t *sb)
7634 {
7635   return (sb != NULL && sb->isSetAnnotation()) ?
7636     safe_strdup(sb->getAnnotationString().c_str()) : NULL;
7637 }
7638 
7639 
7640 LIBSBML_EXTERN
7641 int
SBase_isSetMetaId(const SBase_t * sb)7642 SBase_isSetMetaId (const SBase_t *sb)
7643 {
7644   return (sb != NULL) ? static_cast<int>( sb->isSetMetaId() ) : 0;
7645 }
7646 
7647 
7648 LIBSBML_EXTERN
7649 int
SBase_isSetIdAttribute(const SBase_t * sb)7650 SBase_isSetIdAttribute (const SBase_t *sb)
7651 {
7652   return (sb != NULL) ? static_cast<int>( sb->isSetIdAttribute() ) : 0;
7653 }
7654 
7655 
7656 LIBSBML_EXTERN
7657 int
SBase_isSetName(const SBase_t * sb)7658 SBase_isSetName (const SBase_t *sb)
7659 {
7660   return (sb != NULL) ? static_cast<int>( sb->isSetName() ) : 0;
7661 }
7662 
7663 
7664 LIBSBML_EXTERN
7665 int
SBase_isSetNotes(const SBase_t * sb)7666 SBase_isSetNotes (const SBase_t *sb)
7667 {
7668   return (sb != NULL) ? static_cast<int>( sb->isSetNotes() ) : 0;
7669 }
7670 
7671 
7672 LIBSBML_EXTERN
7673 int
SBase_isSetAnnotation(const SBase_t * sb)7674 SBase_isSetAnnotation (const SBase_t *sb)
7675 {
7676   return (sb != NULL) ? static_cast<int>( sb->isSetAnnotation() ) : 0;
7677 }
7678 
7679 
7680 LIBSBML_EXTERN
7681 int
SBase_isSetSBOTerm(const SBase_t * sb)7682 SBase_isSetSBOTerm (const SBase_t *sb)
7683 {
7684   return (sb != NULL) ? static_cast<int>( sb->isSetSBOTerm() ) : 0;
7685 }
7686 
7687 
7688 LIBSBML_EXTERN
7689 int
SBase_setMetaId(SBase_t * sb,const char * metaid)7690 SBase_setMetaId (SBase_t *sb, const char *metaid)
7691 {
7692   if (sb != NULL)
7693     return (metaid == NULL) ? sb->unsetMetaId() : sb->setMetaId(metaid);
7694   else
7695     return LIBSBML_INVALID_OBJECT;
7696 }
7697 
7698 
7699 LIBSBML_EXTERN
7700 int
SBase_setIdAttribute(SBase_t * sb,const char * id)7701 SBase_setIdAttribute (SBase_t *sb, const char *id)
7702 {
7703   if (sb != NULL)
7704     return (id == NULL) ? sb->unsetIdAttribute() : sb->setIdAttribute(id);
7705   else
7706     return LIBSBML_INVALID_OBJECT;
7707 }
7708 
7709 
7710 LIBSBML_EXTERN
7711 int
SBase_setName(SBase_t * sb,const char * name)7712 SBase_setName (SBase_t *sb, const char *name)
7713 {
7714   if (sb != NULL)
7715     return (name == NULL) ? sb->unsetName() : sb->setName(name);
7716   else
7717     return LIBSBML_INVALID_OBJECT;
7718 }
7719 
7720 
7721 LIBSBML_EXTERN
7722 int
SBase_setSBOTerm(SBase_t * sb,int value)7723 SBase_setSBOTerm (SBase_t *sb, int value)
7724 {
7725   if (sb != NULL)
7726     return sb->setSBOTerm(value);
7727   else
7728     return LIBSBML_INVALID_OBJECT;
7729 }
7730 
7731 
7732 LIBSBML_EXTERN
7733 int
SBase_setSBOTermID(SBase_t * sb,const char * sboid)7734 SBase_setSBOTermID (SBase_t *sb, const char* sboid)
7735 {
7736   if (sb != NULL)
7737     return sb->setSBOTerm(sboid);
7738   else
7739     return LIBSBML_INVALID_OBJECT;
7740 }
7741 
7742 
7743 LIBSBML_EXTERN
7744 int
SBase_setNamespaces(SBase_t * sb,XMLNamespaces_t * xmlns)7745 SBase_setNamespaces (SBase_t *sb, XMLNamespaces_t *xmlns)
7746 {
7747   if (sb != NULL)
7748     return sb->setNamespaces(xmlns);
7749   else
7750     return LIBSBML_INVALID_OBJECT;
7751 }
7752 
7753 
7754 LIBSBML_EXTERN
7755 int
SBase_setNotes(SBase_t * sb,XMLNode_t * notes)7756 SBase_setNotes (SBase_t *sb, XMLNode_t *notes)
7757 {
7758   if (sb != NULL)
7759     return sb->setNotes(notes);
7760   else
7761     return LIBSBML_INVALID_OBJECT;
7762 }
7763 
7764 
7765 LIBSBML_EXTERN
7766 int
SBase_setNotesString(SBase_t * sb,const char * notes)7767 SBase_setNotesString (SBase_t *sb, const char *notes)
7768 {
7769   if (sb != NULL)
7770   {
7771     if(notes == NULL)
7772     {
7773       return sb->unsetNotes();
7774     }
7775     else
7776     {
7777       return sb->setNotes(notes);
7778     }
7779   }
7780   else
7781     return LIBSBML_INVALID_OBJECT;
7782 }
7783 
7784 
7785 LIBSBML_EXTERN
7786 int
SBase_setNotesStringAddMarkup(SBase_t * sb,const char * notes)7787 SBase_setNotesStringAddMarkup (SBase_t *sb, const char *notes)
7788 {
7789   if (sb != NULL)
7790   {
7791     if(notes == NULL)
7792     {
7793       return sb->unsetNotes();
7794     }
7795     else
7796     {
7797       return sb->setNotes(notes, true);
7798     }
7799   }
7800   else
7801     return LIBSBML_INVALID_OBJECT;
7802 }
7803 
7804 
7805 LIBSBML_EXTERN
7806 int
SBase_appendNotes(SBase_t * sb,XMLNode_t * notes)7807 SBase_appendNotes (SBase_t *sb, XMLNode_t *notes)
7808 {
7809   if (sb != NULL)
7810     return sb->appendNotes(notes);
7811   else
7812     return LIBSBML_INVALID_OBJECT;
7813 }
7814 
7815 
7816 LIBSBML_EXTERN
7817 int
SBase_appendNotesString(SBase_t * sb,const char * notes)7818 SBase_appendNotesString (SBase_t *sb, const char *notes)
7819 {
7820   if (sb != NULL)
7821   {
7822     if (notes != NULL)
7823       return sb->appendNotes(notes);
7824     else
7825       return LIBSBML_INVALID_OBJECT;
7826   }
7827   else
7828     return LIBSBML_INVALID_OBJECT;
7829 }
7830 
7831 
7832 LIBSBML_EXTERN
7833 int
SBase_setAnnotation(SBase_t * sb,XMLNode_t * annotation)7834 SBase_setAnnotation (SBase_t *sb, XMLNode_t *annotation)
7835 {
7836   if (sb != NULL)
7837     return sb->setAnnotation(annotation);
7838   else
7839     return LIBSBML_INVALID_OBJECT;
7840 }
7841 
7842 
7843 LIBSBML_EXTERN
7844 int
SBase_setAnnotationString(SBase_t * sb,const char * annotation)7845 SBase_setAnnotationString (SBase_t *sb, const char *annotation)
7846 {
7847   if (sb != NULL)
7848   {
7849     if(annotation == NULL)
7850     {
7851       return sb->unsetAnnotation();
7852     }
7853     else
7854     {
7855       return sb->setAnnotation(annotation);
7856     }
7857   }
7858   else
7859     return LIBSBML_INVALID_OBJECT;
7860 }
7861 
7862 
7863 LIBSBML_EXTERN
7864 int
SBase_appendAnnotation(SBase_t * sb,XMLNode_t * annotation)7865 SBase_appendAnnotation (SBase_t *sb, XMLNode_t *annotation)
7866 {
7867   if (sb != NULL)
7868     return sb->appendAnnotation(annotation);
7869   else
7870     return LIBSBML_INVALID_OBJECT;
7871 }
7872 
7873 
7874 LIBSBML_EXTERN
7875 int
SBase_appendAnnotationString(SBase_t * sb,const char * annotation)7876 SBase_appendAnnotationString (SBase_t *sb, const char *annotation)
7877 {
7878   if (sb != NULL)
7879   {
7880     if (annotation != NULL)
7881       return sb->appendAnnotation(annotation);
7882     else
7883       return LIBSBML_INVALID_OBJECT;
7884   }
7885   else
7886     return LIBSBML_INVALID_OBJECT;
7887 }
7888 
7889 LIBSBML_EXTERN
7890 int
SBase_removeTopLevelAnnotationElement(SBase_t * sb,const char * name)7891 SBase_removeTopLevelAnnotationElement (SBase_t *sb, const char *name)
7892 {
7893   if (sb != NULL)
7894   {
7895     if (name != NULL)
7896       return sb->removeTopLevelAnnotationElement(name);
7897     else
7898       return LIBSBML_INVALID_OBJECT;
7899   }
7900   else
7901     return LIBSBML_INVALID_OBJECT;
7902 }
7903 
7904 
7905 LIBSBML_EXTERN
7906 int
SBase_removeTopLevelAnnotationElementWithURI(SBase_t * sb,const char * name,const char * uri)7907 SBase_removeTopLevelAnnotationElementWithURI (SBase_t *sb, const char *name,
7908                                               const char *uri)
7909 {
7910   if (sb != NULL)
7911   {
7912     if (name != NULL && uri != NULL)
7913       return sb->removeTopLevelAnnotationElement(name, uri);
7914     else
7915       return LIBSBML_INVALID_OBJECT;
7916   }
7917   else
7918     return LIBSBML_INVALID_OBJECT;
7919 }
7920 
7921 
7922 LIBSBML_EXTERN
7923 int
SBase_replaceTopLevelAnnotationElement(SBase_t * sb,XMLNode_t * annotation)7924 SBase_replaceTopLevelAnnotationElement (SBase_t *sb, XMLNode_t *annotation)
7925 {
7926   if (sb != NULL)
7927   {
7928     if (annotation != NULL)
7929       return sb->replaceTopLevelAnnotationElement(annotation);
7930     else
7931       return LIBSBML_INVALID_OBJECT;
7932   }
7933   else
7934     return LIBSBML_INVALID_OBJECT;
7935 }
7936 
7937 
7938 LIBSBML_EXTERN
7939 int
SBase_replaceTopLevelAnnotationElementString(SBase_t * sb,const char * annotation)7940 SBase_replaceTopLevelAnnotationElementString (SBase_t *sb, const char *annotation)
7941 {
7942   if (sb != NULL)
7943   {
7944     if (annotation != NULL)
7945       return sb->replaceTopLevelAnnotationElement(annotation);
7946     else
7947       return LIBSBML_INVALID_OBJECT;
7948   }
7949   else
7950     return LIBSBML_INVALID_OBJECT;
7951 }
7952 
7953 
7954 LIBSBML_EXTERN
7955 int
SBase_unsetMetaId(SBase_t * sb)7956 SBase_unsetMetaId (SBase_t *sb)
7957 {
7958   if (sb != NULL)
7959     return sb->unsetMetaId();
7960   else
7961     return LIBSBML_INVALID_OBJECT;
7962 }
7963 
7964 
7965 LIBSBML_EXTERN
7966 int
SBase_unsetIdAttribute(SBase_t * sb)7967 SBase_unsetIdAttribute (SBase_t *sb)
7968 {
7969   if (sb != NULL)
7970     return sb->unsetIdAttribute();
7971   else
7972     return LIBSBML_INVALID_OBJECT;
7973 }
7974 
7975 
7976 LIBSBML_EXTERN
7977 int
SBase_unsetName(SBase_t * sb)7978 SBase_unsetName (SBase_t *sb)
7979 {
7980   if (sb != NULL)
7981     return sb->unsetName();
7982   else
7983     return LIBSBML_INVALID_OBJECT;
7984 }
7985 
7986 
7987 ///*
7988 //* Unsets the "id" attribute of the given object.
7989 //*
7990 //* @param sb the SBase_t structure.
7991 //*
7992 //* @copydetails doc_returns_success_code
7993 //* @li @link OperationReturnValues_t#LIBSBML_OPERATION_SUCCESS LIBSBML_OPERATION_SUCCESS @endlink
7994 //* @li @link OperationReturnValues_t#LIBSBML_OPERATION_FAILED LIBSBML_OPERATION_FAILED @endlink
7995 //*/
7996 //LIBSBML_EXTERN
7997 //int
7998 //SBase_unsetId (SBase_t *sb)
7999 //{
8000 // return sb->unsetId();
8001 //}
8002 //
8003 
8004 LIBSBML_EXTERN
8005 int
SBase_unsetNotes(SBase_t * sb)8006 SBase_unsetNotes (SBase_t *sb)
8007 {
8008   if (sb != NULL)
8009     return sb->unsetNotes();
8010   else
8011     return LIBSBML_INVALID_OBJECT;
8012 }
8013 
8014 
8015 LIBSBML_EXTERN
8016 int
SBase_unsetAnnotation(SBase_t * sb)8017 SBase_unsetAnnotation (SBase_t *sb)
8018 {
8019   if (sb != NULL)
8020     return sb->unsetAnnotation();
8021   else
8022     return LIBSBML_INVALID_OBJECT;
8023 }
8024 
8025 
8026 LIBSBML_EXTERN
8027 int
SBase_unsetSBOTerm(SBase_t * sb)8028 SBase_unsetSBOTerm (SBase_t *sb)
8029 {
8030   if (sb != NULL)
8031     return sb->unsetSBOTerm();
8032   else
8033     return LIBSBML_INVALID_OBJECT;
8034 }
8035 
8036 
8037 LIBSBML_EXTERN
8038 const Model_t *
SBase_getModel(const SBase_t * sb)8039 SBase_getModel (const SBase_t *sb)
8040 {
8041   return (sb != NULL) ? sb->getModel() : NULL;
8042 }
8043 
8044 LIBSBML_EXTERN
8045 int
SBase_getTypeCode(const SBase_t * sb)8046 SBase_getTypeCode (const SBase_t *sb)
8047 {
8048   return (sb != NULL) ? sb->getTypeCode() : SBML_UNKNOWN;
8049 }
8050 
8051 
8052 LIBSBML_EXTERN
8053 const char *
SBase_getElementName(const SBase_t * sb)8054 SBase_getElementName (const SBase_t *sb)
8055 {
8056   return (sb != NULL && !(sb->getElementName().empty())) ?
8057     sb->getElementName().c_str() : NULL;
8058 }
8059 
8060 
8061 LIBSBML_EXTERN
8062 char *
SBase_getPackageName(const SBaseExtensionPoint_t * sb)8063 SBase_getPackageName(const SBaseExtensionPoint_t *sb)
8064 {
8065   if (sb == NULL) return NULL;
8066   return safe_strdup(sb->getPackageName().c_str());
8067 }
8068 
8069 
8070 LIBSBML_EXTERN
8071 unsigned int
SBase_getLine(const SBase_t * sb)8072 SBase_getLine (const SBase_t *sb)
8073 {
8074   return (sb != NULL) ? sb->getLine() : 0;
8075 }
8076 
8077 
8078 LIBSBML_EXTERN
8079 unsigned int
SBase_getColumn(const SBase_t * sb)8080 SBase_getColumn (const SBase_t *sb)
8081 {
8082   return (sb != NULL) ? sb->getColumn() : 0;
8083 }
8084 
8085 
8086 LIBSBML_EXTERN
8087 int
SBase_hasValidLevelVersionNamespaceCombination(SBase_t * sb)8088 SBase_hasValidLevelVersionNamespaceCombination(SBase_t *sb)
8089 {
8090   return (sb != NULL) ?
8091     static_cast <int> (sb->hasValidLevelVersionNamespaceCombination()) : 0;
8092 }
8093 
8094 
8095 LIBSBML_EXTERN
8096 int
SBase_getNumPlugins(SBase_t * sb)8097 SBase_getNumPlugins(SBase_t *sb)
8098 {
8099   return (sb != NULL) ? (int)sb->getNumPlugins() : 0;
8100 }
8101 
8102 
8103 LIBSBML_EXTERN
8104 SBasePlugin_t*
SBase_getPlugin(SBase_t * sb,const char * package)8105 SBase_getPlugin(SBase_t *sb, const char *package)
8106 {
8107   return (sb != NULL) ? sb->getPlugin(package) : NULL;
8108 }
8109 
8110 LIBSBML_EXTERN
8111 int
SBase_setUserData(SBase_t * sb,void * userData)8112 SBase_setUserData(SBase_t* sb, void *userData)
8113 {
8114   if (sb == NULL) return LIBSBML_INVALID_OBJECT;
8115   return sb->setUserData(userData);
8116 }
8117 
8118 
8119 LIBSBML_EXTERN
8120 void *
SBase_getUserData(const SBase_t * sb)8121 SBase_getUserData(const SBase_t* sb)
8122 {
8123   if (sb == NULL) return NULL;
8124   return sb->getUserData();
8125 }
8126 
8127 LIBSBML_EXTERN
8128 int
SBase_isSetUserData(const SBase_t * sb)8129 SBase_isSetUserData(const SBase_t* sb)
8130 {
8131   if (sb == NULL) return 0;
8132   return static_cast <int>(sb->isSetUserData());
8133 }
8134 
8135 LIBSBML_EXTERN
8136 int
SBase_unsetUserData(SBase_t * sb)8137 SBase_unsetUserData(SBase_t* sb)
8138 {
8139   if (sb == NULL) return LIBSBML_INVALID_OBJECT;
8140   return sb->unsetUserData();
8141 }
8142 
8143 LIBSBML_EXTERN
8144 SBase_t*
SBase_getElementBySId(SBase_t * sb,const char * id)8145 SBase_getElementBySId(SBase_t* sb, const char* id)
8146 {
8147   if (sb == NULL) return NULL;
8148   return sb->getElementBySId(id);
8149 }
8150 
8151 LIBSBML_EXTERN
8152 SBase_t*
SBase_getElementByMetaId(SBase_t * sb,const char * metaid)8153 SBase_getElementByMetaId(SBase_t* sb, const char* metaid)
8154 {
8155   if (sb == NULL) return NULL;
8156   return sb->getElementByMetaId(metaid);
8157 }
8158 
8159 LIBSBML_EXTERN
8160 List_t*
SBase_getAllElements(SBase_t * sb)8161 SBase_getAllElements(SBase_t* sb)
8162 {
8163   if (sb == NULL) return NULL;
8164   return sb->getAllElements();
8165 }
8166 
8167 LIBSBML_EXTERN
8168 void
SBase_renameSIdRefs(SBase_t * sb,const char * oldid,const char * newid)8169 SBase_renameSIdRefs(SBase_t* sb, const char* oldid, const char* newid)
8170 {
8171   if (sb == NULL) return;
8172   return sb->renameSIdRefs(oldid, newid);
8173 }
8174 
8175 LIBSBML_EXTERN
8176 void
SBase_renameMetaIdRefs(SBase_t * sb,const char * oldid,const char * newid)8177 SBase_renameMetaIdRefs(SBase_t* sb, const char* oldid, const char* newid)
8178 {
8179   if (sb == NULL) return;
8180   return sb->renameMetaIdRefs(oldid, newid);
8181 }
8182 
8183 LIBSBML_EXTERN
8184 void
SBase_renameUnitSIdRefs(SBase_t * sb,const char * oldid,const char * newid)8185 SBase_renameUnitSIdRefs(SBase_t* sb, const char* oldid, const char* newid)
8186 {
8187   if (sb == NULL) return;
8188   return sb->renameUnitSIdRefs(oldid, newid);
8189 }
8190 
8191 LIBSBML_EXTERN
8192 SBase_t*
SBase_getElementFromPluginsBySId(SBase_t * sb,const char * id)8193 SBase_getElementFromPluginsBySId(SBase_t* sb, const char* id)
8194 {
8195   if (sb == NULL) return NULL;
8196   return sb->getElementFromPluginsBySId(id);
8197 }
8198 
8199 LIBSBML_EXTERN
8200 SBase_t*
SBase_getElementFromPluginsByMetaId(SBase_t * sb,const char * metaid)8201 SBase_getElementFromPluginsByMetaId(SBase_t* sb, const char* metaid)
8202 {
8203   if (sb == NULL) return NULL;
8204   return sb->getElementFromPluginsByMetaId(metaid);
8205 }
8206 
8207 LIBSBML_EXTERN
8208 List_t*
SBase_getAllElementsFromPlugins(SBase_t * sb)8209 SBase_getAllElementsFromPlugins(SBase_t* sb)
8210 {
8211   if (sb == NULL) return NULL;
8212   return sb->getAllElementsFromPlugins();
8213 }
8214 /** @endcond */
8215 
8216 LIBSBML_CPP_NAMESPACE_END
8217