1 /**
2  * \file    TranslateSBML.cpp
3  * \brief   MATLAB code for translating SBML document into MATLAB structure
4  * \author  Sarah Keating
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 <stdio.h>
43 #include <string.h>
44 
45 #include <mex.h>
46 
47 #ifndef USE_OCTAVE
48 #include <matrix.h>
49 #endif
50 #include <algorithm>
51 
52 #include <sbml/SBMLReader.h>
53 #include <sbml/SBMLTypes.h>
54 #include <sbml/xml/XMLNode.h>
55 #include <sbml/math/ASTNode.h>
56 #include <sbml/extension/SBasePlugin.h>
57 #include <sbml/extension/SBMLExtensionRegistry.h>
58 
59 LIBSBML_CPP_NAMESPACE_USE
60 
61 #ifdef USE_FBC
62 #include <sbml/packages/fbc/common/FbcExtensionTypes.h>
63 #endif
64 
65 ////////////////////////////////
66 
67 // declarations - since a mex file cannot use local includes
68 
69 typedef enum
70 {
71     TYPE_BOOL
72   , TYPE_CHAR
73   , TYPE_DOUBLE
74   , TYPE_INT
75   , TYPE_ELEMENT
76   , TYPE_UINT
77   , TYPE_UNKNOWN
78 } FieldType_t;
79 
80 const char* FIELDTYPE_STRINGS[] =
81 {
82       "bool"
83     , "char"
84     , "double"
85     , "int"
86     , "structure"
87     , "uint"
88 };
89 
90 typedef enum {
91     OTHER_NAME = 0
92   , SBML_NOTES
93   , SBML_ANNOT
94   , OTHER_NAMESPACES
95   , OTHER_CVTERMS
96   , SBML_MATH
97   , SBML_RULE_TYPE
98   , SBML_ISSET
99   , SBML_MESSAGE
100   , OTHER_TIME_SYMBOL
101   , OTHER_DELAY_SYMBOL
102   , OTHER_AVOGADRO_SYMBOL
103   , OTHER_RATEOF_SYMBOL
104   , OTHER_ANOMALOUS_MATH
105   , FBC_ASSOCIATION
106 
107   , SBML_KNOWN_ATT_ELEM = 20
108 
109 } FieldnamesType_t;
110 
111 struct FieldValues_t {
112   std::string fieldName;
113   std::string sbmlName;
114   std::string prefix;
115   FieldType_t type;
116   bool isSBMLAttribute;
117   FieldnamesType_t fieldnameType;
118   std::string strValue;
119   int iValue;
120   double dValue;
121  };
122 
123 
124 class StructureFields
125 {
126 public:
127 
128   StructureFields(SBase* obj, mxArray* structure);
129 
130   StructureFields(SBase* obj);
131 
132   StructureFields(std::string& tc);
133 
134   ~StructureFields();
135 
136 
137   void addAttributes(const std::string& functionId, unsigned int index = 0,
138                      unsigned int total_no = 0);
139 
140   void createStructure(const std::string& functionId, SBase* base, bool usePlugin = false,
141                        const std::string& prefix = "");
142 
getTypeCode() const143   const std::string& getTypeCode() const { return sbmlTC; };
144 
getStructure() const145   mxArray* getStructure() const { return mxStructure; };
146 
147   static const std::string readString(mxArray* mxArray1, const std::string& name,
148                                       unsigned int index);
149 
150   static unsigned int readUint(mxArray* mxArry1, const std::string& name,
151                                unsigned int index);
152 
153   static int readInt(mxArray* mxArry1, const std::string& name, unsigned int index);
154 
155   static void reportReadError(const std::string& type, const std::string& name,
156                        unsigned int index, unsigned int total_no,
157                        const std::string& tc);
158 
159 private:
160   void populateFields();
161 
162   void determineTypeCode();
163 
164   void populateStructure(const std::string& functionId, SBase* base,
165                          unsigned int index);
166 
167   void addStructureField(const std::string& functionId, SBase* base,
168     unsigned int index, FieldValues_t field, bool usePlugin);
169 
170   void addChildElement(FieldValues_t field, unsigned int index);
171 
172   void setAttribute(FieldValues_t field,
173                     unsigned int index = 0, unsigned int total_no = 0);
174 
175 
176   const std::string getFieldname(unsigned int i, const std::string& id);
177   const std::string getDefaultValue(unsigned int i, const std::string& id);
178   void getDefaultValue(unsigned int i, const std::string& id, double& value);
179   void getDefaultValue(unsigned int i, const std::string& id, int& value);
180   const FieldType_t getValueType(unsigned int i, const std::string& id);
181   bool getIsSBMLAttribute(unsigned int i, const std::string& id);
182   const std::string getSBMLPrefix(unsigned int i, const std::string& id);
183   const std::string getSBMLName(unsigned int i, const std::string& id);
184   const FieldnamesType_t getNameEnumType(unsigned int i, const std::string& id);
185 
186   // read values from structure
187   int readInt(const std::string& name, unsigned int index, unsigned int total_no);
188 
189   double readDouble(const std::string& name, unsigned int index, unsigned int total_no);
190 
191   const std::string readString(const std::string& name, unsigned int index, unsigned int total_no);
192 
193   unsigned int readUint(const std::string& name, unsigned int index, unsigned int total_no);
194 
195   // need to further work out which type of rule
196   const std::string getRuleType(mxArray* mxRuleStructure, unsigned int index);
197   std::string getRuleTypeCode(SBase* base);
198   std::string getAssociationTypeCode(SBase* base);
199 
200 
201   void addAnomalousChild(FieldValues_t field);
202 
203   void addAnomalousChildStructure(const std::string& functionId, SBase* base,
204                           unsigned int index, FieldValues_t field);
205 
206   const ASTNode* getMathChild(const std::string& value);
207 
208   char * convertMathFormula(const std::string& pacFormula);
209 
210   void adjustForCSymbols(ASTNode * math);
211 
212   // read values from model or default
213   const std::string getStringValue(const std::string& functionId, SBase* base,
214     FieldValues_t field, bool usePlugin);
215 
216   double getDoubleValue(const std::string& functionId, SBase* base,
217     FieldValues_t field, bool usePlugin);
218 
219   bool getBoolValue(const std::string& functionId, SBase* base,
220     FieldValues_t field, bool usePlugin);
221 
222   unsigned int getUintValue(const std::string& functionId, SBase* base,
223     FieldValues_t field, bool usePlugin);
224 
225   int getIntValue(const std::string& functionId, SBase* base,
226     FieldValues_t field, bool usePlugin);
227 
228   std::string getMathString(SBase* base);
229 
230   char * GetMatlabFormula(char * pacFormula, std::string object);
231 
232   void lookForCSymbols(ASTNode* math);
233 
234   void dealWithTimeSymbol(ASTNode* math);
235 
236   void dealWithDelaySymbol(ASTNode* math);
237 
238   void dealWithAvogadroSymbol(ASTNode* math);
239 
240   void dealWithRateOfSymbol(ASTNode* math);
241 
242   bool determineStatus(const std::string& name, unsigned int index);
243 
244   void reportReadError(const std::string& type, const std::string& name,
245                        unsigned int index, unsigned int total_no);
246 
247 
248   bool usingPlugin(const std::string& prefix, SBase* base = NULL);
249 
250   mxArray* getNamespacesStructure();
251 
252   mxArray* getCVTermsStructure(SBase* base);
253 
254   void addCVTerms(unsigned int index);
255 
256   void freeStructureMemory();
257 
258 protected:
259 
260   mxArray* mxFieldnames;
261   mxArray* mxDefaultValues;
262   mxArray* mxValueTypes;
263 
264   size_t nNumberFields;
265 
266   mxArray* mxStructure;
267 
268   SBase* mSBase;
269   std::string sbmlTC;
270 
271   std::vector<FieldValues_t> mFields;
272 };
273 
274 typedef std::map<const std::string, unsigned int> PkgMap;
275 typedef PkgMap::iterator  PkgIter;
276 
277 class ModelDetails
278 {
279 public:
280   ModelDetails();
281 
282   ModelDetails(SBMLDocument *doc);
283 
~ModelDetails()284   ~ModelDetails() { };
285 
getLevel()286   unsigned int getLevel() {return mLevel; } ;
getVersion()287   unsigned int getVersion() { return mVersion; } ;
288 
getDelaySymbol()289   const std::string& getDelaySymbol() { return mDelaySymbol; } ;
getTimeSymbol()290   const std::string& getTimeSymbol() { return mTimeSymbol; } ;
getAvogadroSymbol()291   const std::string& getAvogadroSymbol() { return mAvogadroSymbol; } ;
getRateOfSymbol()292   const std::string& getRateOfSymbol() { return mRateOfSymbol; } ;
293 
setDelaySymbol(const std::string & symbol)294   void setDelaySymbol(const std::string& symbol) { mDelaySymbol = symbol; } ;
setAvogadroSymbol(const std::string & symbol)295   void setAvogadroSymbol(const std::string& symbol) { mAvogadroSymbol = symbol; } ;
setTimeSymbol(const std::string & symbol)296   void setTimeSymbol(const std::string& symbol) { mTimeSymbol = symbol; } ;
setRateOfSymbol(const std::string & symbol)297   void setRateOfSymbol(const std::string& symbol) { mRateOfSymbol = symbol; } ;
298 
getNamespaces()299   SBMLNamespaces* getNamespaces() { return mSBMLns; };
300 
getPackages()301   PkgMap getPackages() { return mPackageMap; };
302 
303   bool isPackagePresent(const std::string& pkg);
304 
305 
306 protected:
307 
308   void populateNamespaces();
309   void populateNamespaces(SBMLDocument* doc);
310   void populatePkgMap();
311   void populatePkgMap(SBMLDocument* doc);
312   void populateSupportedPackages();
313 
314   bool isSupportedPackageNS(const std::string& uri, const std::string prefix);
315 
316   unsigned int mLevel;
317   unsigned int mVersion;
318 
319   std::string mDelaySymbol;
320   std::string mTimeSymbol;
321   std::string mAvogadroSymbol;
322   std::string mRateOfSymbol;
323 
324   SBMLNamespaces *mSBMLns;
325 
326   IdList mSupportedPackages;
327 
328   PkgMap mPackageMap;
329 
330 };
331 
332 ///////////////////////////////////////////////////////////////////////////////
333 
334 // global variables
335 mxArray *modelArray = NULL;
336 bool freeMemory;
337 ModelDetails * details;
338 
339 IdList reqdPkgPrefixes;
340 IdList unreqdPkgPrefixes;
341 
342 bool fbcUsingId;
343 bool fbcAddGeneProducts;
344 bool onlyExpectedFields;
345 bool applyUserValidation;
346 
347 //////////////////////////////////////////////////////////////////////////////
348 //
349 // StructureFields.cpp
350 
351 //////////////////////////////////////////////////////////////////////////////
352 //
353 // report error/free memory and exit when error encountered
354 
FreeMem(void)355 void FreeMem(void)
356 {
357   /* destroy arrays created */
358   mxDestroyArray(modelArray);
359 }
360 
361 void
reportError(const std::string & id,const std::string & message)362 reportError(const std::string&id, const std::string& message)
363 {
364   if (freeMemory)
365   {
366     FreeMem();
367   }
368 
369   mexErrMsgIdAndTxt(id.c_str(), message.c_str());
370 }
371 
372 ////////////////////////////////////////////////////////////////////////////
373 
374 // useful global functions
375 
376 mxArray *
CreateIntScalar(int nValue)377 CreateIntScalar (int nValue)
378 {
379   mxArray * pArray;
380   int * panData;
381 
382   pArray = mxCreateNumericMatrix(1,1,mxINT32_CLASS, mxREAL);
383   panData = (int *)mxGetData(pArray);
384   panData[0] = nValue;
385 
386   return pArray;
387 }
388 
389 
390 FieldType_t
getFieldType(const char * type)391 getFieldType(const char* type)
392 {
393   if (type != NULL)
394   {
395     const FieldType_t lo = TYPE_BOOL;
396     const FieldType_t hi = (const FieldType_t)(TYPE_UNKNOWN - 1);
397 
398     return (FieldType_t)util_bsearchStringsI(FIELDTYPE_STRINGS, type, lo, hi);
399   }
400   else
401     return TYPE_UNKNOWN;
402 }
403 
404 // only used by OutputSBML
getRequiredStatus(const std::string & prefix)405 bool getRequiredStatus(const std::string& prefix)
406 {
407   bool required = false;
408 
409   if (reqdPkgPrefixes.contains(prefix))
410   {
411     required = true;
412   }
413 
414   return required;
415 }
416 
populatePackageLists()417 void populatePackageLists()
418 {
419   //reqdPkgPrefixes.append("comp");
420   //reqdPkgPrefixes.append("spatial");
421 
422   unreqdPkgPrefixes.append("fbc");
423   unreqdPkgPrefixes.append("qual");
424   unreqdPkgPrefixes.append("groups");
425 }
426 
427 // only used by OutputSBML
428 bool
isUnknownType(std::string tc)429 isUnknownType(std::string tc)
430 {
431   // TO DO
432   if (tc == "(Unknown SBML Type)")
433     return true;
434   else if (tc == "(Unknown SBML Fbc Type)")
435     return true;
436   else if (tc == "(Unknown SBML Groups Type)")
437     return true;
438   else if (tc == "(Unknown SBML Qual Type)")
439     return true;
440   else
441     return false;
442 }
443 
444 //////////////////////////////////////////////////////////////////////////////
445 //
446 // class to store the structure/retrieve fields and write the SBML Model
447 
448 // only used by OutputSBML
StructureFields(SBase * obj,mxArray * structure)449 StructureFields::StructureFields(SBase* obj, mxArray* structure) :
450     mSBase ( NULL)
451   , mxStructure ( NULL )
452   , sbmlTC ("")
453 {
454   mSBase = obj;
455   mxStructure = structure;
456 
457   determineTypeCode();
458   populateFields();
459 }
460 
461 // only used by OutputSBML
StructureFields(SBase * obj)462 StructureFields::StructureFields(SBase* obj) :
463     mSBase ( NULL)
464   , mxStructure ( NULL )
465   , sbmlTC ("")
466 {
467   mSBase = obj;
468 
469   determineTypeCode();
470   populateFields();
471 }
472 
473 // only used by TranslateSBML
StructureFields(std::string & tc)474 StructureFields::StructureFields(std::string& tc) :
475     mSBase ( NULL)
476   , mxStructure ( NULL )
477   , sbmlTC ( tc )
478 {
479   populateFields();
480 }
481 
482 
~StructureFields()483 StructureFields::~StructureFields()
484 {
485   mFields.clear();
486   // must not do this as it can be a part of a larger model
487 //  delete mSBase;
488 
489   // MATLAB says dont call destroy array in a destructor
490   // https://uk.mathworks.com/help/matlab/matlab_external/memory-management-issues.html
491   //mxDestroyArray(mxStructure);
492   //mxDestroyArray(mxFieldnames);
493   //mxDestroyArray(mxDefaultValues);
494   //mxDestroyArray(mxValueTypes);
495 }
496 
497 void
freeStructureMemory()498 StructureFields::freeStructureMemory()
499 {
500   mxDestroyArray(mxFieldnames);
501   mxDestroyArray(mxDefaultValues);
502   mxDestroyArray(mxValueTypes);
503   // do not delete in output as the structure is being recursively used
504   if (mxStructure) mxDestroyArray(mxStructure);
505 }
506 
507 void
determineTypeCode()508 StructureFields::determineTypeCode()
509 {
510   if (!sbmlTC.empty()) return;
511   else if (mSBase == NULL) return;
512 
513   PkgMap pm = details->getPackages();
514 
515   sbmlTC = SBMLTypeCode_toString(mSBase->getTypeCode(), "core");
516   // check whether we are using a package object
517   PkgIter it = pm.begin();
518 
519   while (isUnknownType(sbmlTC) && it != pm.end())
520   {
521     sbmlTC = SBMLTypeCode_toString(mSBase->getTypeCode(), (it->first).c_str());
522     sbmlTC[0] = tolower(sbmlTC[0]);
523     ++it;
524   }
525 }
526 
527 void
populateFields()528 StructureFields::populateFields()
529 {
530   // the array size will need to accomadate all packages
531   PkgMap pm = details->getPackages();
532   mxArray *mxOutputs[4];
533   unsigned int numPlugins = (unsigned int)(pm.size());
534   if (numPlugins > 0)
535   {
536     int numberInputs = 5;
537 
538     mxArray *mxInput[5];
539 
540     std::string id = std::string("StructureFields:populateFields:") + sbmlTC;
541 
542     // hack for level 1 rules
543     if (sbmlTC == "AssignmentRule" || sbmlTC == "RateRule")
544     {
545       int L1TC = ((Rule*)(mSBase))->getL1TypeCode();
546       if (L1TC == SBML_UNKNOWN)
547       {
548         mxInput[0] = mxCreateString(sbmlTC.c_str());
549       }
550       else
551       {
552         mxInput[0] = mxCreateString(SBMLTypeCode_toString(L1TC, "core"));
553       }
554     }
555     else
556     {
557       mxInput[0] = mxCreateString(sbmlTC.c_str());
558     }
559     mxInput[1] = CreateIntScalar(details->getLevel());
560     mxInput[2] = CreateIntScalar(details->getVersion());
561     mwSize dims[1] = { numPlugins };
562     mxInput[3] = mxCreateCellArray(1, dims);
563     mxInput[4] = mxCreateDoubleMatrix(1, numPlugins, mxREAL);
564     double *pinput4 = mxGetPr(mxInput[4]);
565     unsigned int inputCount = 0;
566     for (PkgIter it = pm.begin(); it != pm.end(); ++it)
567     {
568       mxSetCell(mxInput[3], inputCount, mxCreateString((it->first).c_str()));
569       pinput4[inputCount] = it->second;
570       inputCount++;
571     }
572 
573     mxArray * exception = NULL;
574     exception = mexCallMATLABWithTrap(4, mxOutputs, numberInputs, mxInput, "getStructure");
575     if (exception != 0)
576     {
577       mexCallMATLAB(0, (mxArray **)NULL, 1, &exception, "throw");
578 
579       reportError(id, "Failed to get fieldnames");
580     }
581     mxDestroyArray(mxInput[0]);
582     mxDestroyArray(mxInput[1]);
583     mxDestroyArray(mxInput[2]);
584     mxDestroyArray(mxInput[3]);
585     mxDestroyArray(mxInput[4]);
586   }
587   else
588   {
589     int numberInputs = 3;
590 
591     mxArray *mxInput[3];
592 
593     std::string id = std::string("StructureFields:populateFields:") + sbmlTC;
594 
595     // hack for level 1 rules
596     if (sbmlTC == "AssignmentRule" || sbmlTC == "RateRule")
597     {
598       int L1TC = ((Rule*)(mSBase))->getL1TypeCode();
599       if (L1TC == SBML_UNKNOWN)
600       {
601         mxInput[0] = mxCreateString(sbmlTC.c_str());
602       }
603       else
604       {
605         mxInput[0] = mxCreateString(SBMLTypeCode_toString(L1TC, "core"));
606       }
607     }
608     else
609     {
610       mxInput[0] = mxCreateString(sbmlTC.c_str());
611     }
612     mxInput[1] = CreateIntScalar(details->getLevel());
613     mxInput[2] = CreateIntScalar(details->getVersion());
614 
615     mxArray * exception = NULL;
616     exception = mexCallMATLABWithTrap(4, mxOutputs, numberInputs, mxInput, "getStructure");
617     if (exception != 0)
618     {
619       mexCallMATLAB(0, (mxArray **)NULL, 1, &exception, "throw");
620 
621       reportError(id, "Failed to get fieldnames");
622     }
623     mxDestroyArray(mxInput[0]);
624     mxDestroyArray(mxInput[1]);
625     mxDestroyArray(mxInput[2]);
626   }
627 
628   mxFieldnames = mxDuplicateArray(mxOutputs[0]);
629   mxDefaultValues = mxDuplicateArray(mxOutputs[1]);
630   mxValueTypes = mxDuplicateArray(mxOutputs[2]);
631   nNumberFields = (int)mxGetScalar(mxOutputs[3]);
632 
633   mxDestroyArray(mxOutputs[0]);
634   mxDestroyArray(mxOutputs[1]);
635   mxDestroyArray(mxOutputs[2]);
636   mxDestroyArray(mxOutputs[3]);
637 
638   for (unsigned int i = 0; i < nNumberFields; ++i)
639   {
640     FieldValues_t field;
641     field.fieldName = getFieldname(i, "populate");
642     field.type = getValueType(i, "populate");
643     field.sbmlName = getSBMLName(i, "populate");
644     field.prefix = getSBMLPrefix(i, "populate");
645     field.isSBMLAttribute = getIsSBMLAttribute(i, "populate");
646     field.fieldnameType = getNameEnumType(i, "populate");
647     switch (field.type)
648     {
649     case TYPE_BOOL:
650     case TYPE_INT:
651     case TYPE_UINT:
652       getDefaultValue(i, "populate", field.iValue);
653       break;
654     case TYPE_CHAR:
655     case TYPE_UNKNOWN:
656       field.strValue = getDefaultValue(i, "populate");
657       break;
658     case TYPE_DOUBLE:
659       getDefaultValue(i, "populate", field.dValue);
660       break;
661     default:
662       break;
663     }
664     mFields.push_back(field);
665   }
666 }
667 
668 
669 const std::string
getSBMLPrefix(unsigned int i,const std::string & id)670 StructureFields::getSBMLPrefix(unsigned int i, const std::string& id)
671 {
672   mxArray* mxField = mxGetCell(mxFieldnames, i);
673   mxArray* mxAttPrefix = mxGetCell(mxField, 2);
674   size_t nBuflen = (mxGetM(mxAttPrefix)*mxGetN(mxAttPrefix) + 1);
675   char * fieldname = (char *)mxCalloc(nBuflen, sizeof(char));
676   if (mxGetString(mxAttPrefix, (char *)fieldname, (mwSize)(nBuflen)) != 0)
677   {
678     reportError(id, "Failed in getSBMLPrefix");
679   }
680   const std::string f = std::string(fieldname);
681   mxFree(fieldname);
682   return f;
683 }
684 
685 const std::string
getSBMLName(unsigned int i,const std::string & id)686 StructureFields::getSBMLName(unsigned int i, const std::string& id)
687 {
688   mxArray* mxField = mxGetCell(mxFieldnames, i);
689   mxArray* mxAttPrefix = mxGetCell(mxField, 1);
690   size_t nBuflen = (mxGetM(mxAttPrefix)*mxGetN(mxAttPrefix) + 1);
691   char * fieldname = (char *)mxCalloc(nBuflen, sizeof(char));
692   if (mxGetString(mxAttPrefix, (char *)fieldname, (mwSize)(nBuflen)) != 0)
693   {
694     reportError(id, "Failed in getSBMLName");
695   }
696   const std::string f = std::string(fieldname);
697   mxFree(fieldname);
698   return f;
699 }
700 
701 bool
getIsSBMLAttribute(unsigned int i,const std::string & id)702 StructureFields::getIsSBMLAttribute(unsigned int i, const std::string& id)
703 {
704   mxArray* mxField = mxGetCell(mxFieldnames, i);
705   mxArray* mxSBMLAtt = mxGetCell(mxField, 3);
706   int value = (int)mxGetScalar(mxSBMLAtt);
707   if (value == 0) return false;
708   else return true;
709 }
710 
711 const FieldnamesType_t
getNameEnumType(unsigned int i,const std::string & id)712 StructureFields::getNameEnumType(unsigned int i, const std::string& id)
713 {
714   mxArray* mxField = mxGetCell(mxFieldnames, i);
715   mxArray* mxSBMLAtt = mxGetCell(mxField, 4);
716   int value = (int)mxGetScalar(mxSBMLAtt);
717   return (FieldnamesType_t)(value);
718 
719 }
720 
721 const std::string
getFieldname(unsigned int i,const std::string & id)722 StructureFields::getFieldname(unsigned int i, const std::string& id)
723 {
724   mxArray* mxField = mxGetCell(mxFieldnames, i);
725   mxArray* mxName = mxGetCell(mxField, 0);
726   size_t nBuflen = (mxGetM(mxName)*mxGetN(mxName)+1);
727   char * fieldname = (char *) mxCalloc(nBuflen, sizeof(char));
728   if (mxGetString(mxName, (char *) fieldname, (mwSize)(nBuflen)) != 0)
729   {
730     reportError(id, "Failed in GetFieldname");
731   }
732   const std::string f = std::string(fieldname);
733   mxFree(fieldname);
734   return f;
735 }
736 
737 const std::string
getDefaultValue(unsigned int i,const std::string & id)738 StructureFields::getDefaultValue(unsigned int i, const std::string& id)
739 {
740   mxArray* mxName = mxGetCell(mxDefaultValues, i);
741   size_t nBuflen = (mxGetM(mxName)*mxGetN(mxName)+1);
742   char * fieldname = (char *) mxCalloc(nBuflen, sizeof(char));
743   if (mxGetString(mxName, (char *) fieldname, (mwSize)(nBuflen)) != 0)
744   {
745     reportError(id, "Failed in GetDefaultValue");
746   }
747   const std::string f = std::string(fieldname);
748   mxFree(fieldname);
749   return f;
750 }
751 
752 void
getDefaultValue(unsigned int i,const std::string & id,double & value)753 StructureFields::getDefaultValue(unsigned int i, const std::string& id, double& value)
754 {
755   mxArray* mxName = mxGetCell(mxDefaultValues, i);
756   value = (double) mxGetScalar(mxName);
757 }
758 
759 void
getDefaultValue(unsigned int i,const std::string & id,int & value)760 StructureFields::getDefaultValue(unsigned int i, const std::string& id, int& value)
761 {
762   mxArray* mxName = mxGetCell(mxDefaultValues, i);
763   value = (int) mxGetScalar(mxName);
764 }
765 
766 const FieldType_t
getValueType(unsigned int i,const std::string & id)767 StructureFields::getValueType(unsigned int i, const std::string& id)
768 {
769   mxArray* mxName = mxGetCell(mxValueTypes, i);
770   size_t nBuflen = (mxGetM(mxName)*mxGetN(mxName)+1);
771   char * fieldname = (char *) mxCalloc(nBuflen, sizeof(char));
772   if (mxGetString(mxName, (char *) fieldname, (mwSize)(nBuflen)) != 0)
773   {
774     mxFree(fieldname);
775     reportError(id, "Failed in GetValueType");
776   }
777   FieldType_t ft = getFieldType(fieldname);
778   mxFree(fieldname);
779   return ft;
780 }
781 
782 //////////////////////////
783 
784 // functions for creating structure from SBML
785 
786 void
createStructure(const std::string & functionId,SBase * base,bool usePlugin,const std::string & prefix)787 StructureFields::createStructure(const std::string& functionId, SBase* base,
788                                  bool usePlugin, const std::string& prefix)
789 {
790   std::string fieldname;
791   unsigned int total_no = base->getNumObjects(sbmlTC);
792   if (usePlugin)
793   {
794     total_no = base->getPlugin(prefix)->getNumObjects(sbmlTC);
795   }
796   mwSize dims[2] = {1, total_no};
797 
798   char **field_names = (char**)(safe_malloc(nNumberFields * sizeof(char*)));
799   for (unsigned int i = 0; i < nNumberFields; ++i)
800   {
801     fieldname = mFields.at(i).fieldName;
802     field_names[i] = (char*)(safe_malloc((fieldname.size() * sizeof(char))+ 1));
803     field_names[i] = safe_strdup(fieldname.c_str());
804   }
805 
806   mxStructure = mxCreateStructArray(2, dims, nNumberFields, (const char**)(field_names));
807   safe_free(field_names);
808 
809   for (unsigned int i = 0; i < total_no; ++i)
810   {
811     SBase* child = base->getObject(sbmlTC, i);
812     if (usePlugin)
813     {
814       child = base->getPlugin(prefix)->getObject(sbmlTC, i);
815     }
816     populateStructure(functionId, child, i);
817   }
818 
819 }
820 
821 void
populateStructure(const std::string & functionId,SBase * base,unsigned int index)822 StructureFields::populateStructure(const std::string& functionId, SBase* base, unsigned int index)
823 {
824   if (base == NULL) return;
825 
826   FieldType_t type;
827   FieldnamesType_t nameType;
828 
829   for (unsigned int i = 0; i < nNumberFields; ++i)
830   {
831     FieldValues_t field = mFields.at(i);
832     type = field.type;
833     nameType = field.fieldnameType;
834     bool usePlugin = usingPlugin(field.prefix, base);
835 
836     if (type == TYPE_ELEMENT)
837     {
838       switch (nameType) {
839       case OTHER_NAMESPACES:
840           mxSetField(mxStructure, index, field.fieldName.c_str(), getNamespacesStructure());
841           break;
842       case OTHER_CVTERMS:
843           mxSetField(mxStructure, index, field.fieldName.c_str(), getCVTermsStructure(base));
844           break;
845       default:
846           StructureFields *sf = new StructureFields(field.sbmlName);
847           sf->createStructure(functionId + ":" + field.fieldName, base, usePlugin, field.prefix);
848           mxSetField(mxStructure, index, field.fieldName.c_str(), mxDuplicateArray(sf->getStructure()));
849           sf->freeStructureMemory();
850           delete sf;
851           break;
852       }
853     }
854     else if (field.fieldnameType == OTHER_ANOMALOUS_MATH)
855     {
856       addAnomalousChildStructure(functionId, base, index, field);
857     }
858     else
859     {
860       addStructureField(functionId, base, index, field, usePlugin);
861     }
862 
863   }
864 }
865 
866 void
addAnomalousChildStructure(const std::string & functionId,SBase * base,unsigned int index,FieldValues_t field)867 StructureFields::addAnomalousChildStructure(const std::string& functionId, SBase* base,
868                          unsigned int index, FieldValues_t field)
869 {
870   std::string value;
871   SBase* child = base->getObject(field.fieldName, 0);
872   if (child == NULL)
873   {
874     value = field.strValue;
875   }
876   else
877   {
878     value = getMathString(child);
879   }
880 
881   mxSetField(mxStructure, index, field.fieldName.c_str() ,mxCreateString(value.c_str()));
882 }
883 
884 mxArray*
getNamespacesStructure()885 StructureFields::getNamespacesStructure()
886 {
887   mxArray* mxNSReturn = NULL;
888 
889   const XMLNamespaces * NS = details->getNamespaces()->getNamespaces();
890   int n = NS->getLength();
891   mwSize dims[2] = {1, (mwSize)(n)};
892 
893   /* fields within a namespace structure */
894   const int nNoFields = 2;
895   const char *field_names[] = {
896     "prefix",
897     "uri"
898   };
899 
900 
901   const char * pacPrefix = NULL;
902   const char * pacURI = NULL;
903 
904   int i;
905 
906   mxNSReturn = mxCreateStructArray(2, dims, nNoFields, field_names);
907 
908   for (i = 0; i < n; ++i)
909   {
910     pacPrefix = safe_strdup(NS->getPrefix(i).c_str());
911     pacURI    = safe_strdup(NS->getURI(i).c_str());
912 
913     /**
914     * check for NULL strings - Matlab doesnt like creating
915     * a string that is NULL
916     */
917     if (pacPrefix == NULL) {
918       pacPrefix = "";
919     }
920     if (pacURI == NULL) {
921       pacURI = "";
922     }
923 
924     mxSetField(mxNSReturn, i, "prefix", mxCreateString(pacPrefix));
925     mxSetField(mxNSReturn, i, "uri",    mxCreateString(pacURI));
926 
927     safe_free((void*)(pacPrefix));
928     safe_free((void*)(pacURI));
929   }
930 
931   return mxNSReturn;
932 }
933 
934 mxArray*
createCVTermStructure(int num)935 createCVTermStructure(int num)
936 {
937   mxArray* mxCVTermReturn;
938   mwSize dims[2] = {1, (mwSize)(num)};
939 
940   /* fields within a cvterm structure */
941   const int nNoFields = 4;
942   const char *field_names[] = {
943     "qualifierType",
944     "qualifier",
945     "resources",
946     "cvterms"
947   };
948 
949   mxCVTermReturn = mxCreateStructArray(2, dims, nNoFields, field_names);
950 
951   return mxCVTermReturn;
952 }
953 
954 
955 
956 void
addCVTerm(mxArray * mxCVTermReturn,int i,CVTerm * cv)957   addCVTerm (mxArray* mxCVTermReturn, int i, CVTerm* cv)
958 {
959   const char * pacQualifier = NULL;
960   const char * pacQualifierType = NULL;
961   mxArray* mxResources = NULL;
962 
963   if (cv->getQualifierType() == BIOLOGICAL_QUALIFIER)
964   {
965     std::string bq = "biological";
966     pacQualifierType = (char*)(safe_malloc((bq.size() * sizeof(char))+ 1));
967     pacQualifierType = safe_strdup(bq.c_str());
968 
969     size_t s = sizeof((const char *)(BiolQualifierType_toString(cv->getBiologicalQualifierType()))) * sizeof(char);
970     pacQualifier = (char*)(safe_malloc(s + 1));
971     pacQualifier = safe_strdup(BiolQualifierType_toString(cv->getBiologicalQualifierType()));
972   }
973   else if  (cv->getQualifierType() == MODEL_QUALIFIER)
974   {
975     std::string bq = "model";
976     pacQualifierType = (char*)(safe_malloc((bq.size() * sizeof(char))+ 1));
977     pacQualifierType = safe_strdup(bq.c_str());
978 
979     size_t s = sizeof((const char *)(ModelQualifierType_toString(cv->getModelQualifierType()))) * sizeof(char);
980     pacQualifier = (char*)(safe_malloc(s + 1));
981     pacQualifier = safe_strdup(ModelQualifierType_toString(cv->getModelQualifierType()));
982   }
983   else
984   {
985     std::string bq = "unknown";
986     pacQualifierType = (char*)(safe_malloc((bq.size() * sizeof(char))+ 1));
987     pacQualifierType = safe_strdup(bq.c_str());
988 
989     pacQualifier = (char*)(safe_malloc((bq.size() * sizeof(char))+ 1));
990     pacQualifier = safe_strdup(bq.c_str());
991 
992   }
993   mwSize num = cv->getNumResources();
994   std::string fieldname;
995 
996   char **resources = (char**)(safe_malloc(num * sizeof(char*)));
997   for (unsigned int j = 0; j < num; j++)
998   {
999     fieldname = cv->getResourceURI(j);
1000     size_t s = (fieldname.size() * sizeof(char)) + 1;
1001     resources[j] = (char*)(safe_malloc(s));
1002     resources[j] = safe_strdup(fieldname.c_str());
1003   }
1004 
1005   mxResources = mxCreateCellMatrix(1, num);
1006   for (unsigned int j = 0; j < num; j++)
1007   {
1008     mxSetCell(mxResources, j, mxCreateString(resources[j]));
1009   }
1010 
1011   mxSetField(mxCVTermReturn, i, "qualifierType", mxCreateString(pacQualifierType));
1012   mxSetField(mxCVTermReturn, i, "qualifier", mxCreateString(pacQualifier));
1013   mxSetField(mxCVTermReturn, i, "resources",   mxResources);
1014 
1015   unsigned int numNested = cv->getNumNestedCVTerms();
1016   if (cv->getNumNestedCVTerms() > 0)
1017   {
1018     mxArray* mxNested = createCVTermStructure(numNested);
1019     for (unsigned int j = 0; j < numNested; j++)
1020     {
1021       addCVTerm(mxNested, j, cv->getNestedCVTerm(j));
1022     }
1023     mxSetField(mxCVTermReturn, i, "cvterms",   mxNested);
1024   }
1025 
1026   safe_free((void*)(pacQualifier));
1027   safe_free((void*)(pacQualifierType));
1028   safe_free(resources);
1029 }
1030 
1031 
1032 mxArray*
getCVTermsStructure(SBase * base)1033 StructureFields::getCVTermsStructure(SBase* base)
1034 {
1035   mxArray* mxCVTermReturn = NULL;
1036 
1037   int n = base->getNumCVTerms();
1038   if (n > 0)
1039   {
1040     mxCVTermReturn = createCVTermStructure(n);
1041   }
1042 
1043   for (int i = 0; i < n; ++i)
1044   {
1045     CVTerm * cv = base->getCVTerm(i);
1046     addCVTerm(mxCVTermReturn, i, cv);
1047   }
1048 
1049   return mxCVTermReturn;
1050 }
1051 
1052 
1053 void
addStructureField(const std::string & functionId,SBase * base,unsigned int index,FieldValues_t field,bool usePlugin)1054 StructureFields::addStructureField(const std::string& functionId, SBase* base,
1055   unsigned int index, FieldValues_t field,
1056   bool usePlugin)
1057 {
1058   std::string value;
1059   int ivalue;
1060   unsigned int uvalue;
1061   bool bvalue;
1062   double dvalue;
1063   switch (field.type)
1064   {
1065   case TYPE_UNKNOWN:
1066 
1067   case TYPE_CHAR:
1068     value = getStringValue(functionId, base, field, usePlugin);
1069     mxSetField(mxStructure, index, field.fieldName.c_str(), mxCreateString(value.c_str()));
1070     break;
1071   case TYPE_BOOL:
1072     bvalue = getBoolValue(functionId, base, field, usePlugin);
1073     mxSetField(mxStructure, index, field.fieldName.c_str(), CreateIntScalar(bvalue));
1074     break;
1075   case TYPE_UINT:
1076     uvalue = getUintValue(functionId, base, field, usePlugin);
1077     mxSetField(mxStructure, index, field.fieldName.c_str(), CreateIntScalar(uvalue));
1078     break;
1079   case TYPE_INT:
1080     ivalue = getIntValue(functionId, base, field, usePlugin);
1081     mxSetField(mxStructure, index, field.fieldName.c_str(), CreateIntScalar(ivalue));
1082     break;
1083   case TYPE_DOUBLE:
1084     dvalue = getDoubleValue(functionId, base, field, usePlugin);
1085     mxSetField(mxStructure, index, field.fieldName.c_str(), mxCreateDoubleScalar(dvalue));
1086     break;
1087   case TYPE_ELEMENT:
1088   default:
1089     break;
1090   }
1091 }
1092 
1093 const std::string
getStringValue(const std::string & functionId,SBase * base,FieldValues_t field,bool usePlugin)1094 StructureFields::getStringValue(const std::string& functionId, SBase* base,
1095   FieldValues_t field,
1096   bool usePlugin)
1097 {
1098   std::string value;
1099 
1100   if (field.isSBMLAttribute)
1101   {
1102     bool useDefault = true;
1103     switch (field.fieldnameType)
1104     {
1105     case SBML_NOTES:
1106       value = base->getNotesString();
1107       useDefault = false;
1108       break;
1109     case SBML_ANNOT:
1110       value = base->getAnnotationString();
1111       useDefault = false;
1112       break;
1113     case SBML_MESSAGE:
1114       value = base->getMessageString();
1115       useDefault = false;
1116       break;
1117     case SBML_MATH:
1118       value = getMathString(base);
1119       useDefault = false;
1120       break;
1121     default:
1122       if (!usePlugin && base->isSetAttribute(field.sbmlName))
1123       {
1124         base->getAttribute(field.sbmlName, value);
1125         useDefault = false;
1126       }
1127       else if (usePlugin && base->getPlugin(field.prefix)->isSetAttribute(field.sbmlName))
1128       {
1129         base->getPlugin(field.prefix)->getAttribute(field.sbmlName, value);
1130         useDefault = false;
1131       }
1132       break;
1133 
1134     }
1135 #ifdef USE_FBC
1136 
1137     if (field.fieldnameType == FBC_ASSOCIATION)
1138     {
1139       value = static_cast<FbcAssociation*>(base)->toInfix(fbcUsingId);//FbcAssociation_toInfix(static_cast<FbcAssociation*>(base));
1140       useDefault = false;
1141     }
1142 #endif
1143 
1144     if (useDefault)
1145     {
1146       value = field.strValue;// getDefaultValue(fieldIndex, functionId);
1147     }
1148   }
1149   else
1150   {
1151     switch (field.fieldnameType)
1152     {
1153     case SBML_RULE_TYPE:
1154       value = field.strValue;// getDefaultValue(fieldIndex, functionId);
1155       if (field.fieldName == "type" && base->getTypeCode() == SBML_RATE_RULE)
1156       {
1157         value = "rate";
1158       }
1159       break;
1160     case OTHER_AVOGADRO_SYMBOL:
1161       if (!details->getAvogadroSymbol().empty())
1162       {
1163         value = details->getAvogadroSymbol();
1164       }
1165       else
1166       {
1167         value = field.strValue;// getDefaultValue(fieldIndex, functionId);
1168       }
1169       break;
1170     case OTHER_DELAY_SYMBOL:
1171       if (!details->getDelaySymbol().empty())
1172       {
1173         value = details->getDelaySymbol();
1174       }
1175       else
1176       {
1177         value = field.strValue;// getDefaultValue(fieldIndex, functionId);
1178       }
1179       break;
1180     case OTHER_TIME_SYMBOL:
1181       if (!details->getTimeSymbol().empty())
1182       {
1183         value = details->getTimeSymbol();
1184       }
1185       else
1186       {
1187         value = field.strValue;// getDefaultValue(fieldIndex, functionId);
1188       }
1189       break;
1190     case OTHER_RATEOF_SYMBOL:
1191       if (!details->getRateOfSymbol().empty())
1192       {
1193         value = details->getRateOfSymbol();
1194       }
1195       else
1196       {
1197         value = field.strValue;// getDefaultValue(fieldIndex, functionId);
1198       }
1199       break;
1200     default:
1201       value = field.strValue;// getDefaultValue(fieldIndex, functionId);
1202      /* hack for rules that all use the same fieldnames/defaults */
1203       if (value == "SBML_ALGEBRAIC_RULE")
1204       {
1205         value = getRuleTypeCode(base);
1206       }
1207       else if (value == "SBML_FBC_ASSOCIATION")
1208       {
1209         value = getAssociationTypeCode(base);
1210       }
1211       break;
1212     }
1213   }
1214 
1215   return (const std::string)(value);
1216 }
1217 
1218 double
getDoubleValue(const std::string & functionId,SBase * base,FieldValues_t field,bool usePlugin)1219 StructureFields::getDoubleValue(const std::string& functionId, SBase* base,
1220   FieldValues_t field,
1221   bool usePlugin)
1222 {
1223   double value;
1224 
1225   if (field.isSBMLAttribute)
1226   {
1227     if (!usePlugin && base->isSetAttribute(field.sbmlName))
1228     {
1229       base->getAttribute(field.sbmlName, value);
1230     }
1231     else if (usePlugin && base->getPlugin(field.prefix)->isSetAttribute(field.sbmlName))
1232     {
1233       base->getPlugin(field.prefix)->getAttribute(field.sbmlName, value);
1234     }
1235     else
1236     {
1237       value = field.dValue;
1238     }
1239   }
1240   else
1241   {
1242     value = field.dValue;
1243   }
1244 
1245   return value;
1246 }
1247 
1248 
1249 int
getIntValue(const std::string & functionId,SBase * base,FieldValues_t field,bool usePlugin)1250 StructureFields::getIntValue(const std::string& functionId, SBase* base,
1251   FieldValues_t field,
1252   bool usePlugin)
1253 {
1254   int value;
1255 
1256   if (field.isSBMLAttribute)
1257   {
1258     if (!usePlugin && base->isSetAttribute(field.sbmlName))
1259     {
1260       base->getAttribute(field.sbmlName, value);
1261     }
1262     else if (usePlugin && base->getPlugin(field.prefix)->isSetAttribute(field.sbmlName))
1263     {
1264       base->getPlugin(field.prefix)->getAttribute(field.sbmlName, value);
1265     }
1266     else
1267     {
1268       value = field.iValue;
1269     }
1270   }
1271   else
1272   {
1273     value = field.iValue;
1274   }
1275 
1276   return value;
1277 }
1278 
1279 
1280 unsigned int
getUintValue(const std::string & functionId,SBase * base,FieldValues_t field,bool usePlugin)1281 StructureFields::getUintValue(const std::string& functionId, SBase* base,
1282   FieldValues_t field,
1283   bool usePlugin)
1284 {
1285   unsigned int value;
1286   int ivalue;
1287   bool useDefault = false;
1288   if (field.isSBMLAttribute)
1289   {
1290     if (!usePlugin && base->isSetAttribute(field.sbmlName))
1291     {
1292       base->getAttribute(field.sbmlName, value);
1293     }
1294     else if (usePlugin && base->getPlugin(field.prefix)->isSetAttribute(field.sbmlName))
1295     {
1296       base->getPlugin(field.prefix)->getAttribute(field.sbmlName, value);
1297     }
1298     else
1299     {
1300       ivalue = field.iValue;// getDefaultValue(fieldIndex, functionId, ivalue);
1301       useDefault = true;
1302     }
1303   }
1304   else
1305   {
1306     ivalue = field.iValue;
1307     useDefault = true;
1308   }
1309 
1310   if (useDefault)
1311   {
1312     return (unsigned int)(ivalue);
1313   }
1314   else
1315   {
1316     return value;
1317   }
1318 }
1319 
1320 
1321 bool
getBoolValue(const std::string & functionId,SBase * base,FieldValues_t field,bool usePlugin)1322 StructureFields::getBoolValue(const std::string& functionId, SBase* base,
1323   FieldValues_t field,
1324   bool usePlugin)
1325 {
1326   bool bvalue;
1327   int value;
1328   if (field.isSBMLAttribute)
1329   {
1330     if (!usePlugin && base->isSetAttribute(field.sbmlName))
1331     {
1332       base->getAttribute(field.sbmlName, bvalue);
1333       return bvalue;
1334     }
1335     else if (usePlugin && base->getPlugin(field.prefix)->isSetAttribute(field.sbmlName))
1336     {
1337       base->getPlugin(field.prefix)->getAttribute(field.sbmlName, bvalue);
1338       return bvalue;
1339     }
1340     else
1341     {
1342       value = field.iValue;// getDefaultValue(fieldIndex, functionId, value);
1343     }
1344   }
1345   else if (field.fieldnameType == SBML_ISSET)
1346   {
1347     if (!usePlugin)
1348     {
1349       value = base->isSetAttribute(field.sbmlName);
1350     }
1351     else
1352     {
1353       value = base->getPlugin(field.prefix)->isSetAttribute(field.sbmlName);
1354     }
1355   }
1356   else
1357   {
1358     value = field.iValue;// getDefaultValue(fieldIndex, functionId, value);
1359   }
1360 
1361   return (value == 0) ? false : true;
1362 }
1363 
1364 
1365 std::string
getMathString(SBase * base)1366 StructureFields::getMathString(SBase* base)
1367 {
1368   const ASTNode* ast = base->getMath();
1369   lookForCSymbols(const_cast<ASTNode*>(ast));
1370   char * formula = SBML_formulaToString(ast);
1371   char * matlab = GetMatlabFormula(formula, sbmlTC);
1372   std::string math = std::string(matlab);
1373   mxFree(matlab);
1374   return math;
1375 
1376 }
1377 
1378 char *
GetMatlabFormula(char * pacFormula,std::string object)1379 StructureFields::GetMatlabFormula(char * pacFormula, std::string object)
1380 {
1381   mxArray *mxInput[1];
1382   mxArray *mxOutput[1];
1383   int nStatus;
1384   size_t nBuflen;
1385   char * formula;
1386 
1387   /* convert MathML infix formula to MATLAB */
1388 
1389   mxInput[0] = mxCreateString(pacFormula);
1390   nStatus = mexCallMATLAB(1, mxOutput, 1, mxInput, "CheckAndConvert");
1391 
1392   if (nStatus != 0)
1393   {
1394     std::string id = std::string("TranslateSBML:GetMatlabFormula:") + object;
1395     reportError(id.c_str(), "Failed to convert formula");
1396   }
1397 
1398   /* get the formula returned */
1399   nBuflen = (mxGetM(mxOutput[0])*mxGetN(mxOutput[0])+1);
1400   formula = (char *) mxCalloc(nBuflen, sizeof(char));
1401   nStatus = mxGetString(mxOutput[0], (char *) formula, (mwSize)(nBuflen));
1402 
1403   if (nStatus != 0)
1404   {
1405     std::string id = std::string("TranslateSBML:GetMatlabFormula") + object;
1406     reportError(id.c_str(), "Cannot copy formula");
1407   }
1408 
1409   mxDestroyArray(mxInput[0]);
1410   mxDestroyArray(mxOutput[0]);
1411 
1412   return formula;
1413 }
1414 
1415 void
lookForCSymbols(ASTNode * math)1416 StructureFields::lookForCSymbols(ASTNode* math)
1417 {
1418   if (math == NULL) return;
1419 
1420   unsigned int nChild = math->getNumChildren();
1421   ASTNodeType_t type = math->getType();
1422 
1423   switch (type)
1424   {
1425   case AST_NAME_AVOGADRO:
1426     dealWithAvogadroSymbol(math);
1427     break;
1428   case AST_NAME_TIME:
1429     dealWithTimeSymbol(math);
1430     break;
1431   case AST_FUNCTION_DELAY:
1432     dealWithDelaySymbol(math);
1433     break;
1434   case AST_FUNCTION_RATE_OF:
1435     dealWithRateOfSymbol(math);
1436     break;
1437   default:
1438     break;
1439   }
1440 
1441   for (unsigned int i = 0; i < nChild; ++i)
1442   {
1443     ASTNode* child = math->getChild(i);
1444     lookForCSymbols(child);
1445   }
1446 }
1447 
1448 void
dealWithAvogadroSymbol(ASTNode * math)1449 StructureFields::dealWithAvogadroSymbol(ASTNode* math)
1450 {
1451   if (math == NULL) return;
1452   if (details->getAvogadroSymbol().empty())
1453   {
1454     details->setAvogadroSymbol(math->getName());
1455   }
1456   else
1457   {
1458     math->setName(details->getAvogadroSymbol().c_str());
1459   }
1460 }
1461 
1462 void
dealWithTimeSymbol(ASTNode * math)1463 StructureFields::dealWithTimeSymbol(ASTNode* math)
1464 {
1465   if (math == NULL) return;
1466   if (details->getTimeSymbol().empty())
1467   {
1468     details->setTimeSymbol(math->getName());
1469   }
1470   else
1471   {
1472     math->setName(details->getTimeSymbol().c_str());
1473   }
1474 }
1475 
1476 void
dealWithDelaySymbol(ASTNode * math)1477 StructureFields::dealWithDelaySymbol(ASTNode* math)
1478 {
1479   if (math == NULL) return;
1480   if (details->getDelaySymbol().empty())
1481   {
1482     details->setDelaySymbol(math->getName());
1483   }
1484   else
1485   {
1486     math->setName(details->getDelaySymbol().c_str());
1487   }
1488 }
1489 
1490 void
dealWithRateOfSymbol(ASTNode * math)1491 StructureFields::dealWithRateOfSymbol(ASTNode* math)
1492 {
1493   if (math == NULL) return;
1494   if (details->getRateOfSymbol().empty())
1495   {
1496     details->setRateOfSymbol(math->getName());
1497   }
1498   else
1499   {
1500     math->setName(details->getRateOfSymbol().c_str());
1501   }
1502 }
1503 
1504 //////////////////////////////////////////////////////////////
1505 
1506 // general need to know function
1507 
1508 bool
usingPlugin(const std::string & prefix,SBase * base)1509 StructureFields::usingPlugin(const std::string& prefix, SBase* base)
1510 {
1511   bool usePlugin = false;
1512   if (prefix.size() > 0)
1513   {
1514     if (mSBase != NULL && mSBase->getPackageName() != prefix)
1515     {
1516       usePlugin = true;
1517     }
1518     else if (base != NULL && base->getPlugin(prefix) != NULL)
1519     {
1520       usePlugin = true;
1521     }
1522   }
1523 
1524   return usePlugin;
1525 }
1526 
1527 //////////////////////////
1528 
1529 // functions for creating SBML from structure
1530 void
addAttributes(const std::string & functionId,unsigned int index,unsigned int total_no)1531 StructureFields::addAttributes(const std::string& functionId, unsigned int index,
1532                                unsigned int total_no)
1533 {
1534   FieldType_t type;
1535   FieldnamesType_t nameType;
1536 
1537   for (unsigned int i = 0; i < nNumberFields; ++i)
1538   {
1539     FieldValues_t field = mFields.at(i);
1540     type = field.type;
1541     nameType = field.fieldnameType;
1542     if (nameType != OTHER_CVTERMS && !field.isSBMLAttribute)
1543     {
1544       continue;
1545     }
1546     if (type == TYPE_ELEMENT)
1547     {
1548       if (nameType == OTHER_CVTERMS)
1549       {
1550         addCVTerms(index);
1551       }
1552       else
1553       {
1554        addChildElement(field, index);
1555       }
1556     }
1557     else if (field.fieldnameType == OTHER_ANOMALOUS_MATH)
1558     {
1559       addAnomalousChild(field);
1560     }
1561     else
1562     {
1563       setAttribute(field, index, total_no);
1564     }
1565 
1566   }
1567 }
1568 
1569 CVTerm *
getCVTerm(mxArray * mxCVTerms,unsigned int i)1570 getCVTerm(mxArray* mxCVTerms, unsigned int i)
1571 {
1572   CVTerm *cv;
1573   std::string qualType = StructureFields::readString(mxCVTerms, "qualifierType", i);
1574   std::string qual = StructureFields::readString(mxCVTerms, "qualifier", i);
1575   if (qualType == "biological")
1576   {
1577     cv = new CVTerm(BIOLOGICAL_QUALIFIER);
1578     cv->setBiologicalQualifierType(qual);
1579   }
1580   else if (qualType == "model")
1581   {
1582     cv = new CVTerm(MODEL_QUALIFIER);
1583     cv->setModelQualifierType(qual);
1584   }
1585   else
1586   {
1587     cv = new CVTerm();
1588   }
1589 
1590   mxArray* mxResources = mxGetField(mxCVTerms, i, "resources");
1591   size_t numRes = mxGetNumberOfElements(mxResources);
1592 
1593   for (unsigned int j = 0; j < numRes; j++)
1594   {
1595     mxArray* mxField = mxGetCell(mxResources, j);
1596     char *value = mxArrayToString(mxField);
1597     if (value != NULL)
1598     {
1599       cv->addResource(std::string(value));
1600     }
1601   }
1602 
1603   mxArray* mxNestedCV = mxGetField(mxCVTerms, i, "cvterms");
1604   if (mxNestedCV != NULL)
1605   {
1606     size_t numNested = mxGetNumberOfElements(mxNestedCV);
1607 
1608     for (unsigned int n = 0; n < numNested; n++)
1609     {
1610       CVTerm *nested = getCVTerm(mxNestedCV, n);
1611       cv->addNestedCVTerm(nested);
1612       delete nested;
1613     }
1614   }
1615 
1616   return cv;
1617 }
1618 
1619 void
addCVTerms(unsigned int index)1620 StructureFields::addCVTerms(unsigned int index)
1621 {
1622   mxArray* mxCVTerms = mxGetField(mxStructure, index, "cvterms");
1623   if (mxCVTerms == NULL)
1624     return;
1625 
1626   size_t numCV = mxGetNumberOfElements(mxCVTerms);
1627 
1628   for (unsigned int i = 0; i < numCV; ++i)
1629   {
1630     CVTerm *cv = getCVTerm(mxCVTerms, i);
1631     if (!mSBase->isSetMetaId())
1632       mSBase->setMetaId("temp");
1633     mSBase->addCVTerm(cv);
1634     delete cv;
1635   }
1636 
1637 }
1638 
1639 void
addChildElement(FieldValues_t field,unsigned int index)1640 StructureFields::addChildElement(FieldValues_t field, unsigned int index)
1641 {
1642   mxArray* mxChild = mxGetField(mxStructure, index, field.fieldName.c_str());
1643   SBase *pChild = NULL;
1644 
1645   size_t n = mxGetNumberOfElements(mxChild);
1646   if (mxChild == NULL) return;
1647   else if (n == 0) return;
1648 
1649   bool usePlugin = usingPlugin(field.prefix);
1650 
1651   for (unsigned int i = 0; i < n; ++i)
1652   {
1653     // hack for rules - since a list of rules contains assignmentRule etc..
1654     if (field.fieldName == "rule")
1655     {
1656       pChild = mSBase->createChildObject(getRuleType(mxChild, i));
1657     }
1658     else
1659     {
1660       if (usePlugin)
1661       {
1662         pChild = mSBase->getPlugin(field.prefix)->createChildObject(field.sbmlName);
1663       }
1664       else
1665       {
1666         pChild = mSBase->createChildObject(field.sbmlName);
1667       }
1668     }
1669 
1670     if (pChild != NULL)
1671     {
1672       StructureFields *sf = new StructureFields(pChild, mxChild);
1673 
1674       std::string id = std::string("OutputSBML:addChildElement:") + sf->getTypeCode();
1675       sf->addAttributes(id, i, n);
1676 
1677       sf->freeStructureMemory();
1678     }
1679   }
1680 }
1681 
1682 void
addAnomalousChild(FieldValues_t field)1683 StructureFields::addAnomalousChild(FieldValues_t field)
1684 {
1685   std::string value = readString(field.fieldName, 0, 0);
1686 
1687   if (!value.empty())
1688   {
1689     SBase *pChild = mSBase->createChildObject(field.fieldName);
1690     if (pChild != NULL)
1691     {
1692       std::string value = readString(field.fieldName, 0, 0);
1693       const ASTNode* ast = getMathChild(value);
1694       pChild->setMath(ast);
1695    }
1696   }
1697 }
1698 
1699 const ASTNode*
getMathChild(const std::string & value)1700 StructureFields::getMathChild(const std::string& value)
1701 {
1702   /* convert MATLAB formula to MathML infix */
1703   char * cvalue = convertMathFormula(value);
1704   L3ParserSettings settings;
1705   settings.setParseLog(L3P_PARSE_LOG_AS_LN);
1706   const ASTNode *ast = SBML_parseL3FormulaWithSettings(cvalue, &settings);
1707   adjustForCSymbols(const_cast<ASTNode*>(ast));
1708   mxFree(cvalue);
1709   return ast;
1710 }
1711 
1712 void
adjustForCSymbols(ASTNode * math)1713 StructureFields::adjustForCSymbols(ASTNode * math)
1714 {
1715   if (math == NULL)
1716   {
1717     return;
1718   }
1719 
1720   ASTNodeType_t type = math->getType();
1721   switch (type)
1722   {
1723   case AST_FUNCTION:
1724     if (math->getName() == details->getDelaySymbol())
1725     {
1726       math->setType(AST_FUNCTION_DELAY);
1727     }
1728     else if (math->getName() == details->getRateOfSymbol())
1729     {
1730       math->setType(AST_FUNCTION_RATE_OF);
1731     }
1732     break;
1733   case AST_NAME:
1734     if (math->getName() == details->getTimeSymbol())
1735     {
1736       math->setType(AST_NAME_TIME);
1737     }
1738     else if (math->getName() == details->getAvogadroSymbol())
1739     {
1740       math->setType(AST_NAME_AVOGADRO);
1741     }
1742     break;
1743   default:
1744     break;
1745   }
1746 
1747   for (unsigned int i = 0; i < math->getNumChildren(); ++i)
1748   {
1749     adjustForCSymbols(math->getChild(i));
1750   }
1751 }
1752 
1753 
1754 void
setAttribute(FieldValues_t field,unsigned int index,unsigned int total_no)1755 StructureFields::setAttribute(FieldValues_t field,
1756                               unsigned int index, unsigned int total_no)
1757 {
1758   std::string value;
1759   int ivalue;
1760   unsigned int uvalue;
1761   bool bvalue;
1762   double dvalue;
1763   bool usePlugin = usingPlugin(field.prefix);
1764   const ASTNode *ast = NULL;
1765 
1766   switch(field.type)
1767   {
1768   case TYPE_CHAR:
1769     value = readString(field.fieldName, index, total_no);
1770     switch (field.fieldnameType) {
1771     case SBML_MATH:
1772       ast = getMathChild(value);
1773       mSBase->setMath(ast);
1774       break;
1775     case SBML_NOTES:
1776       mSBase->setNotes(value);
1777       break;
1778     case SBML_ANNOT:
1779       mSBase->setAnnotation(value);
1780       break;
1781     case SBML_MESSAGE:
1782       mSBase->setMessage(value);
1783       break;
1784     default:
1785       if (usePlugin)
1786       {
1787         mSBase->getPlugin(field.prefix)->setAttribute(field.sbmlName, value);
1788       }
1789       else
1790       {
1791         mSBase->setAttribute(field.sbmlName, value);
1792       }
1793       break;
1794     }
1795     break;
1796 
1797   case TYPE_INT:
1798     ivalue = readInt(field.fieldName, index, total_no);
1799     if (determineStatus(field.fieldName, index))
1800     {
1801       if (usePlugin)
1802       {
1803         mSBase->getPlugin(field.prefix)->setAttribute(field.sbmlName, ivalue);
1804       }
1805       else
1806       {
1807         mSBase->setAttribute(field.sbmlName, ivalue);
1808       }
1809     }
1810     break;
1811 
1812   case TYPE_UINT:
1813     uvalue = readUint(field.fieldName, index, total_no);
1814     if (determineStatus(field.fieldName, index))
1815     {
1816       if (usePlugin)
1817       {
1818         mSBase->getPlugin(field.prefix)->setAttribute(field.sbmlName, uvalue);
1819       }
1820       else
1821       {
1822         mSBase->setAttribute(field.sbmlName, uvalue);
1823       }
1824     }
1825     break;
1826 
1827   case TYPE_DOUBLE:
1828     dvalue = readDouble(field.fieldName, index, total_no);
1829     if (determineStatus(field.fieldName, index))
1830     {
1831       if (usePlugin)
1832       {
1833         mSBase->getPlugin(field.prefix)->setAttribute(field.sbmlName, dvalue);
1834       }
1835       else
1836       {
1837         mSBase->setAttribute(field.sbmlName, dvalue);
1838       }
1839     }
1840     break;
1841 
1842   case TYPE_BOOL:
1843     ivalue = readInt(field.fieldName, index, total_no);
1844     bvalue = true ? ivalue == 1 : false;
1845     if (determineStatus(field.fieldName, index))
1846     {
1847       if (usePlugin)
1848       {
1849         mSBase->getPlugin(field.prefix)->setAttribute(field.sbmlName, bvalue);
1850       }
1851       else
1852       {
1853         mSBase->setAttribute(field.sbmlName, bvalue);
1854       }
1855     }
1856 
1857   case TYPE_UNKNOWN:
1858   default:
1859     break;
1860   }
1861 }
1862 
1863 const std::string
getRuleType(mxArray * mxRuleStructure,unsigned int index)1864 StructureFields::getRuleType(mxArray* mxRuleStructure, unsigned int index)
1865 {
1866   std::string value = readString(mxRuleStructure, "typecode", index);
1867   std::string retvalue;
1868   if (value == "SBML_ALGEBRAIC_RULE")
1869   {
1870     retvalue = "algebraicRule";
1871   }
1872   else if (value == "SBML_ASSIGNMENT_RULE")
1873   {
1874     retvalue = "assignmentRule";
1875   }
1876   else if (value == "SBML_RATE_RULE")
1877   {
1878     retvalue = "rateRule";
1879   }
1880   else
1881   {
1882     std::string type = readString(mxRuleStructure, "type", index);
1883     if (value == "SBML_PARAMETER_RULE")
1884       if (type == "scalar")
1885         retvalue = "parameterAssignmentRule";
1886       else
1887         retvalue = "parameterRateRule";
1888     else if (value == "SBML_SPECIES_CONCENTRATION_RULE")
1889       if (type == "scalar")
1890         retvalue = "speciesAssignmentRule";
1891       else
1892         retvalue = "speciesRateRule";
1893     else if (value == "SBML_COMPARTMENT_VOLUME_RULE")
1894       if (type == "scalar")
1895         retvalue = "compartmentAssignmentRule";
1896       else
1897         retvalue = "compartmentRateRule";
1898     else
1899       retvalue = "rule";
1900   }
1901 
1902   return retvalue;
1903 }
1904 
1905 std::string
getAssociationTypeCode(SBase * base)1906 StructureFields::getAssociationTypeCode(SBase* base)
1907 {
1908   std::string value = SBMLTypeCode_toString(base->getTypeCode(), "fbc");
1909   std::string retvalue = "SBML_FBC_ASSOCIATION";
1910   if (value == "GeneProductRef")
1911   {
1912     retvalue = "SBML_FBC_GENE_PRODUCT_REF";
1913   }
1914   else if (value == "FbcAnd")
1915   {
1916     retvalue = "SBML_FBC_AND";
1917   }
1918   else if (value == "FbcOr")
1919   {
1920     retvalue = "SBML_FBC_OR";
1921   }
1922   return retvalue;
1923 }
1924 
1925 std::string
getRuleTypeCode(SBase * base)1926 StructureFields::getRuleTypeCode(SBase* base)
1927 {
1928   std::string value = SBMLTypeCode_toString(base->getTypeCode(), "core");
1929   std::string retvalue = "rule";
1930   if (value == "AlgebraicRule")
1931   {
1932     retvalue = "SBML_ALGEBRAIC_RULE";
1933   }
1934   else if (value == "AssignmentRule")
1935   {
1936     if (base->getLevel() > 1)
1937     {
1938       retvalue = "SBML_ASSIGNMENT_RULE";
1939     }
1940     else
1941     {
1942       Model *m = static_cast<Model*>(base->getAncestorOfType(SBML_MODEL));
1943       if (m != NULL)
1944       {
1945         if (m->getCompartment(static_cast<Rule*>(base)->getVariable()) != NULL)
1946         {
1947           retvalue = "SBML_COMPARTMENT_VOLUME_RULE";
1948         }
1949         if (m->getSpecies(static_cast<Rule*>(base)->getVariable()) != NULL)
1950         {
1951           retvalue = "SBML_SPECIES_CONCENTRATION_RULE";
1952         }
1953         if (m->getParameter(static_cast<Rule*>(base)->getVariable()) != NULL)
1954         {
1955           retvalue = "SBML_PARAMETER_RULE";
1956         }
1957       }
1958     }
1959   }
1960   else if (value == "RateRule")
1961   {
1962     if (base->getLevel() > 1)
1963     {
1964       retvalue = "SBML_RATE_RULE";
1965     }
1966     else
1967     {
1968       Model *m = static_cast<Model*>(base->getAncestorOfType(SBML_MODEL));
1969       if (m != NULL)
1970       {
1971         std::string var = static_cast<Rule*>(base)->getVariable();
1972         if (m->getCompartment(var) != NULL)
1973         {
1974           retvalue = "SBML_COMPARTMENT_VOLUME_RULE";
1975         }
1976         if (m->getSpecies(var) != NULL)
1977         {
1978           retvalue = "SBML_SPECIES_CONCENTRATION_RULE";
1979         }
1980         if (m->getParameter(var) != NULL)
1981         {
1982           retvalue = "SBML_PARAMETER_RULE";
1983         }
1984       }
1985     }
1986   }
1987   return retvalue;
1988 }
1989 
1990 
1991 char *
convertMathFormula(const std::string & pacFormula)1992 StructureFields::convertMathFormula(const std::string& pacFormula)
1993 {
1994   mxArray *mxInput[1];
1995   mxArray *mxOutput[1];
1996   int nStatus;
1997   size_t nBuflen;
1998   char * formula;
1999 
2000   /* convert MATLAB formula to MathML infix */
2001 
2002   mxInput[0] = mxCreateString(pacFormula.c_str());
2003   nStatus = mexCallMATLAB(1, mxOutput, 1, mxInput, "ConvertFormulaToMathML");
2004 
2005   if (nStatus != 0)
2006   {
2007     std::string id = std::string("OutputSBML:GetMathMLFormula:") + sbmlTC;
2008     reportError(id, "Failed to convert formula");
2009   }
2010 
2011   /* get the formula returned */
2012   nBuflen = (mxGetM(mxOutput[0])*mxGetN(mxOutput[0])+1);
2013   formula = (char *) mxCalloc(nBuflen, sizeof(char));
2014   nStatus = mxGetString(mxOutput[0], (char *) formula, (mwSize)(nBuflen));
2015 
2016   if (nStatus != 0)
2017   {
2018     std::string id = std::string("OutputSBML:GetMathMLFormula") + sbmlTC;
2019     reportError(id, "Cannot copy formula");
2020   }
2021 
2022   mxDestroyArray(mxInput[0]);
2023   mxDestroyArray(mxOutput[0]);
2024 
2025   return formula;
2026 }
2027 
2028 int
readInt(const std::string & name,unsigned int index,unsigned int total_no)2029 StructureFields::readInt(const std::string& name, unsigned int index, unsigned int total_no)
2030 {
2031   mxArray * mxField;
2032   int value = 0;
2033   int nStatus = 1;
2034 
2035   /* get field */
2036   mxField = mxGetField(mxStructure, index, name.c_str());
2037   if (mxField != NULL)
2038   {
2039     if (!mxIsEmpty(mxField))
2040     {
2041       if (mxIsNumeric(mxField))
2042       {
2043         value = (int)(mxGetScalar(mxField));
2044         nStatus = 0;
2045       }
2046     }
2047     else
2048     {
2049       value = 0;
2050       nStatus = 0;
2051     }
2052 
2053     if (nStatus != 0)
2054     {
2055       reportReadError("Int", name, index, total_no);
2056     }
2057   }
2058   return value;
2059 }
2060 
2061 // static version
2062 int
readInt(mxArray * mxArray1,const std::string & name,unsigned int index)2063 StructureFields::readInt(mxArray* mxArray1, const std::string& name, unsigned int index)
2064 {
2065   mxArray * mxField;
2066   int value = 0;
2067   int nStatus = 1;
2068 
2069   /* get field */
2070   mxField = mxGetField(mxArray1, index, name.c_str());
2071   if (mxField != NULL)
2072   {
2073     if (!mxIsEmpty(mxField))
2074     {
2075       if (mxIsNumeric(mxField))
2076       {
2077         value = (int)(mxGetScalar(mxField));
2078         nStatus = 0;
2079       }
2080     }
2081     else
2082     {
2083       value = 0;
2084       nStatus = 0;
2085     }
2086 
2087     if (nStatus != 0)
2088     {
2089       reportReadError("Int", name, index, 0, "static");
2090     }
2091   }
2092 
2093   return value;
2094 }
2095 
2096 double
readDouble(const std::string & name,unsigned int index,unsigned int total_no)2097 StructureFields::readDouble(const std::string& name, unsigned int index, unsigned int total_no)
2098 {
2099   mxArray * mxField;
2100   double value = 0;
2101   int nStatus = 1;
2102 
2103   /* get field */
2104   mxField = mxGetField(mxStructure, index, name.c_str());
2105   if (mxField != NULL)
2106   {
2107     if (!mxIsEmpty(mxField))
2108     {
2109       if (mxIsNumeric(mxField))
2110       {
2111         value = mxGetScalar(mxField);
2112         nStatus = 0;
2113       }
2114     }
2115     else
2116     {
2117       value = util_NaN();
2118       nStatus = 0;
2119     }
2120 
2121     if (nStatus != 0)
2122     {
2123       reportReadError("Double", name, index, total_no);
2124     }
2125   }
2126   return value;
2127 }
2128 
2129 const std::string
readString(const std::string & name,unsigned int index,unsigned int total_no)2130 StructureFields::readString(const std::string& name, unsigned int index, unsigned int total_no)
2131 {
2132   mxArray * mxField;
2133   char *value = NULL;
2134   int nStatus = 1;
2135   std::string f = "";
2136 
2137   /* get field */
2138   mxField = mxGetField(mxStructure, index, name.c_str());
2139   if (mxField != NULL)
2140   {
2141     value = mxArrayToString(mxField);
2142     if (value != NULL)
2143     {
2144       nStatus = 0;
2145       f = std::string(value);
2146     }
2147 
2148     if (nStatus != 0)
2149     {
2150       reportReadError("String", name, index, total_no);
2151     }
2152   }
2153   return f;
2154 }
2155 
2156 //static version
2157 const std::string
readString(mxArray * mxArray1,const std::string & name,unsigned int index)2158 StructureFields::readString(mxArray* mxArray1, const std::string& name, unsigned int index)
2159 {
2160   mxArray * mxField;
2161   char *value = NULL;
2162   int nStatus = 1;
2163   std::string f = "";
2164   /* get field */
2165   mxField = mxGetField(mxArray1, index, name.c_str());
2166   if (mxField != NULL)
2167   {
2168     value = mxArrayToString(mxField);
2169     if (value != NULL)
2170     {
2171       nStatus = 0;
2172       f = std::string(value);
2173     }
2174     if (nStatus != 0)
2175     {
2176       reportReadError("String", name, index, 0, "static");
2177     }
2178   }
2179   return f;
2180 }
2181 
2182 unsigned int
readUint(const std::string & name,unsigned int index,unsigned int total_no)2183 StructureFields::readUint(const std::string& name, unsigned int index, unsigned int total_no)
2184 {
2185   mxArray * mxField;
2186   unsigned int value = 0;
2187   int nStatus = 1;
2188 
2189   /* get field */
2190   mxField = mxGetField(mxStructure, index, name.c_str());
2191   if (mxField != NULL)
2192   {
2193     if (!mxIsEmpty(mxField))
2194     {
2195       if (mxIsNumeric(mxField))
2196       {
2197         value = (unsigned int)(mxGetScalar(mxField));
2198         nStatus = 0;
2199       }
2200     }
2201     else
2202     {
2203       value = 0;
2204       nStatus = 0;
2205     }
2206 
2207     if (nStatus != 0)
2208     {
2209       reportReadError("Uint", name, index, total_no);
2210     }
2211   }
2212 
2213   return value;
2214 }
2215 
2216 // static version
2217 unsigned int
readUint(mxArray * mxArray1,const std::string & name,unsigned int index)2218 StructureFields::readUint(mxArray* mxArray1, const std::string& name,
2219                           unsigned int index)
2220 {
2221   mxArray * mxField;
2222   unsigned int value = 0;
2223   int nStatus = 1;
2224 
2225   /* get field */
2226   mxField = mxGetField(mxArray1, index, name.c_str());
2227   if (mxField != NULL)
2228   {
2229     if (!mxIsEmpty(mxField))
2230     {
2231       if (mxIsNumeric(mxField))
2232       {
2233         value = (unsigned int)(mxGetScalar(mxField));
2234         nStatus = 0;
2235       }
2236     }
2237     else
2238     {
2239       value = 0;
2240       nStatus = 0;
2241     }
2242 
2243     if (nStatus != 0)
2244     {
2245       reportReadError("Uint", name, index, 0, "static");
2246     }
2247   }
2248   return value;
2249 }
2250 
2251 bool
determineStatus(const std::string & name,unsigned int index)2252 StructureFields::determineStatus(const std::string& name, unsigned int index)
2253 {
2254   bool setStatus = true;
2255   mxArray * mxField;
2256   // if the field itself is empty then it is clearly not set
2257   mxField = mxGetField(mxStructure, index, name.c_str());
2258   if (mxField == NULL || mxIsEmpty(mxField))
2259   {
2260     return false;
2261   }
2262 
2263   // want to know whether there is an isSetXYZ field coming from matlab
2264   // and if so what is its value
2265   unsigned int value = 0;
2266   int nStatus = 1;
2267   const char * cname = name.c_str();
2268   char * cpname = safe_strdup(cname);
2269   const char * isset = "isSet";
2270   char * isSet = safe_strcat(isset, cpname);
2271   cpname[0] = toupper(cpname[0]);
2272   char * isSet1 = safe_strcat(isset, cpname);
2273 
2274   /* get field */
2275   mxField = mxGetField(mxStructure, index, isSet1);
2276   // possibly have isSet followed by lower case
2277   if (mxField == NULL)
2278     mxField = mxGetField(mxStructure, index, isSet);
2279   if (mxField != NULL)
2280   {
2281     if (!mxIsEmpty(mxField) && mxIsNumeric(mxField))
2282     {
2283       value = (unsigned int)(mxGetScalar(mxField));
2284       nStatus = 0;
2285     }
2286 
2287     if (nStatus == 0)
2288     {
2289       setStatus = true ? value == 1 : false;
2290     }
2291   }
2292 
2293   safe_free(cpname);
2294   safe_free(isSet);
2295   safe_free(isSet1);
2296 
2297   return setStatus;
2298 }
2299 ///////////////////////////////////////////
2300 
2301 // report error
2302 
2303 void
reportReadError(const std::string & type,const std::string & name,unsigned int index,unsigned int total_no)2304 StructureFields::reportReadError(const std::string& type, const std::string& name,
2305                                  unsigned int index, unsigned int total_no)
2306 {
2307    std::string mid = "OutputSBML:read" + type + ":" + sbmlTC;
2308 
2309    std::ostringstream errMsg;
2310    if (total_no == 0)
2311      errMsg << " Cannot copy " << sbmlTC << "." << name << " field";
2312    else
2313      errMsg << " Cannot copy " << sbmlTC << "(" << index+1 << ")." << name << " field";
2314 
2315    reportError(mid, errMsg.str());
2316 }
2317 
2318 // static version
2319 void
reportReadError(const std::string & type,const std::string & name,unsigned int index,unsigned int total_no,const std::string & tc)2320 StructureFields::reportReadError(const std::string& type, const std::string& name,
2321                                  unsigned int index, unsigned int total_no,
2322                                  const std::string& tc)
2323 {
2324    std::string mid = "OutputSBML:read" + type + ":" + tc;
2325 
2326    std::ostringstream errMsg;
2327    if (total_no == 0)
2328      errMsg << " Cannot copy " << tc << "." << name << " field";
2329    else
2330      errMsg << " Cannot copy " << tc << "(" << index+1 << ")." << name << " field";
2331 
2332    reportError(mid, errMsg.str());
2333 }
2334 
2335 ///////////////////////////////////////////////////////////////////////////////
2336 //
2337 // class to store model details
2338 
ModelDetails()2339 ModelDetails::ModelDetails()
2340 {
2341   mPackageMap.clear();
2342   mSupportedPackages.clear();
2343 
2344   mLevel = StructureFields::readUint(modelArray, "SBML_level", 0);
2345   mVersion = StructureFields::readUint(modelArray, "SBML_version", 0);
2346 
2347   mDelaySymbol = StructureFields::readString(modelArray, "delay_symbol", 0);
2348   mTimeSymbol = StructureFields::readString(modelArray, "time_symbol", 0);
2349   mAvogadroSymbol = StructureFields::readString(modelArray, "avogadro_symbol", 0);
2350 
2351   populateNamespaces();
2352   populatePkgMap();
2353 }
2354 
ModelDetails(SBMLDocument * doc)2355 ModelDetails::ModelDetails(SBMLDocument* doc)
2356 {
2357   mPackageMap.clear();
2358   mSupportedPackages.clear();
2359 
2360   mLevel = doc->getLevel();
2361   mVersion = doc->getVersion();
2362 
2363   mDelaySymbol = "";
2364   mTimeSymbol = "";
2365   mAvogadroSymbol = "";
2366 
2367   populateNamespaces(doc);
2368   populatePkgMap(doc);
2369 }
2370 
2371 
2372 void
populateNamespaces()2373 ModelDetails::populateNamespaces()
2374 {
2375   mSBMLns = new SBMLNamespaces(getLevel(), getVersion());
2376 
2377   XMLNamespaces *xmlns = new XMLNamespaces();
2378   mxArray* mxNamespaces = mxGetField(modelArray, 0, "namespaces");
2379   size_t nNoNamespaces = mxGetNumberOfElements(mxNamespaces);
2380 
2381   for (unsigned int i = 0; i < nNoNamespaces; ++i)
2382   {
2383     std::string uri = StructureFields::readString(mxNamespaces, "uri", i);
2384     std::string prefix = StructureFields::readString(mxNamespaces, "prefix", i);
2385     xmlns->add(uri, prefix);
2386   }
2387 
2388   mSBMLns->addNamespaces(xmlns);
2389 }
2390 
2391 void
populateNamespaces(SBMLDocument * doc)2392 ModelDetails::populateNamespaces(SBMLDocument* doc)
2393 {
2394   mSBMLns = doc->getSBMLNamespaces();
2395 }
2396 
2397 void
populateSupportedPackages()2398 ModelDetails::populateSupportedPackages()
2399 {
2400   for (unsigned int i = 0; i <  SBMLExtensionRegistry::getNumRegisteredPackages(); ++i)
2401   {
2402     mSupportedPackages.append(SBMLExtensionRegistry::getRegisteredPackageName(i));
2403   }
2404 }
2405 
2406 void
populatePkgMap()2407 ModelDetails::populatePkgMap()
2408 {
2409   populateSupportedPackages();
2410   XMLNamespaces *xmlns = mSBMLns->getNamespaces();
2411   for (int i = 0; i < xmlns->getNumNamespaces(); ++i)
2412   {
2413     if (isSupportedPackageNS(xmlns->getURI(i), xmlns->getPrefix(i)))
2414     {
2415       std::string prefix = xmlns->getPrefix(i);
2416       std::string name = prefix + "_version";
2417       unsigned int version = StructureFields::readUint(modelArray, name, 0);
2418       mPackageMap.insert(std::pair<const std::string, unsigned int>(prefix, version));
2419     }
2420   }
2421 }
2422 
2423 void
populatePkgMap(SBMLDocument * doc)2424 ModelDetails::populatePkgMap(SBMLDocument* doc)
2425 {
2426   populateSupportedPackages();
2427   XMLNamespaces *xmlns = mSBMLns->getNamespaces();
2428   for (int i = 0; i < xmlns->getNumNamespaces(); ++i)
2429   {
2430     if (isSupportedPackageNS(xmlns->getURI(i), xmlns->getPrefix(i)))
2431     {
2432       std::string prefix = xmlns->getPrefix(i);
2433       unsigned int version = doc->getPlugin(prefix)->getPackageVersion();
2434       mPackageMap.insert(std::pair<const std::string, unsigned int>(prefix, version));
2435     }
2436   }
2437 }
2438 
2439 bool
isSupportedPackageNS(const std::string & uri,const std::string prefix)2440 ModelDetails::isSupportedPackageNS(const std::string& uri, const std::string prefix)
2441 {
2442   bool supported = false;
2443   if (prefix.empty())
2444     return supported;
2445 
2446   size_t pos = uri.find("http://www.sbml.org/sbml/level3/version");
2447   if (pos == 0 && mSupportedPackages.contains(prefix))
2448   {
2449     supported = true;
2450   }
2451 
2452   return supported;
2453 }
2454 
2455 bool
isPackagePresent(const std::string & pkg)2456 ModelDetails::isPackagePresent(const std::string& pkg)
2457 {
2458   bool present = false;
2459 
2460   for (PkgIter it = mPackageMap.begin(); it != mPackageMap.end(); ++it)
2461   {
2462     if (it->first == pkg)
2463     {
2464       present = true;
2465       break;
2466     }
2467   }
2468   return present;
2469 }
2470 
2471 ////////////////////////////////////////////////////////////////////////////
2472 //
2473 // Filenames.cpp
2474 
2475 ////////////////////////////////////////////////////////////////////////////
2476 //
2477 // ensure reading of unicode filenames
2478 
2479 #if defined(WIN32) && !defined(CYGWIN) && !defined(USE_OCTAVE)
2480 #define FILE_CHAR wchar_t*
2481 #define FILE_FOPEN(file) _wfopen(file, L"r")
2482 #define USE_FILE_WCHAR 1
2483 #else
2484 #define FILE_CHAR char*
2485 #define FILE_FOPEN(file) fopen(file, "r")
2486 #endif
2487 
2488 #ifndef uint16_t
2489 #define uint16_t unsigned short
2490 #endif
2491 
2492 
readUnicodeString(const mxArray * prhs,mwSize length)2493 FILE_CHAR readUnicodeString(const mxArray *prhs, mwSize length)
2494 {
2495 #ifdef USE_OCTAVE
2496   char* ansii = (char *) mxCalloc(length, sizeof(char));
2497   mxGetString(prhs, ansii, length);
2498   return ansii;
2499 #else
2500   wchar_t* utf16 = (wchar_t *) mxCalloc(length, sizeof(wchar_t));
2501   char* utf8 = NULL;
2502   uint16_T *ch = (uint16_T *) mxGetData(prhs);
2503   wchar_t* p = utf16;
2504   mwSize i;
2505   for ( i = 0; i < length-1; ++i)
2506     *p++ = *ch++;
2507   *p = 0;
2508 
2509 #if USE_FILE_WCHAR
2510   return utf16;
2511 #else
2512 
2513   utf8 = (char*)mxCalloc(length*2, sizeof(char));
2514 
2515   wcstombs(utf8, utf16, length*2);
2516 
2517   /*mxFree(utf16);*/
2518 
2519   if (utf8 != NULL && strlen(utf8) == 0 && length > 0)
2520   {
2521     reportError("readUnicodeString",
2522       "This string uses characters that cannot be "
2523       "expressed in UTF8, please rename the file.");
2524   }
2525 
2526   return utf8;
2527 #endif /* USE_FILE_WCHAR */
2528 
2529 #endif /* USE_OCTAVE*/
2530 
2531 }
2532 
2533 
readUnicodeStringFromArrays(mxArray * mxFilename[2])2534 FILE_CHAR readUnicodeStringFromArrays(mxArray *mxFilename[2])
2535 
2536 {
2537   mwSize nBuflen = (mxGetM(mxFilename[0])*mxGetN(mxFilename[0])+1);
2538   FILE_CHAR pacTempString1 = readUnicodeString(mxFilename[0],nBuflen);
2539 
2540   mwSize nBufferLen = (mxGetM(mxFilename[1])*mxGetN(mxFilename[1])+1);
2541   FILE_CHAR  pacTempString2 = readUnicodeString(mxFilename[1],nBufferLen);
2542 
2543 #if USE_FILE_WCHAR
2544   FILE_CHAR  pacFilename = (wchar_t *) mxCalloc(nBufferLen+nBuflen, sizeof(wchar_t));
2545   wcscpy(pacFilename, pacTempString2);
2546   wcscat(pacFilename, pacTempString1);
2547 #else
2548   FILE_CHAR  pacFilename = (char *) mxCalloc(nBufferLen+nBuflen, sizeof(char));
2549   strcpy(pacFilename, pacTempString2);
2550   strcat(pacFilename, pacTempString1);
2551 #endif
2552 
2553   /*mxFree(pacTempString1);*/
2554   /*mxFree(pacTempString2);*/
2555   return pacFilename;
2556 }
2557 
2558 #if USE_FILE_WCHAR
2559 
endsWith(const wchar_t * fileName,const char * ext)2560 int endsWith(const wchar_t* fileName, const char* ext)
2561 {
2562   size_t len = wcslen(fileName), i;
2563   size_t targetLen = strlen(ext);
2564   wchar_t* temp1 =  (wchar_t*)malloc((targetLen + 1) * sizeof(wchar_t));
2565   char* temp2 =  (char*)malloc((targetLen+1)*sizeof(char));
2566   int result = 0;
2567 
2568   memset(temp1, 0, targetLen*sizeof(wchar_t));
2569   memset(temp2, 0, targetLen*sizeof(char));
2570 
2571   for (i = 0; i < targetLen; ++i)
2572   {
2573     temp1[i] = fileName[len - targetLen + i];
2574   }
2575 
2576   wcstombs(temp2,temp1, targetLen);
2577   result = strcmp_insensitive(temp2, ext);
2578 
2579   /*mxFree(temp1);*/
2580   /*mxFree(temp2);*/
2581   free(temp1);
2582   free(temp2);
2583   return result;
2584 }
2585 
2586 #endif
2587 
2588 FILE_CHAR
browseForFilename()2589 browseForFilename()
2590 {
2591   FILE_CHAR filename = NULL;
2592   mxArray * mxFilename[2], * mxExt[1];
2593   mxExt[0] = mxCreateString(".xml");
2594   int nStatus = mexCallMATLAB(2, mxFilename, 1, mxExt, "uigetfile");
2595 
2596   if (nStatus != 0)
2597   {
2598     reportError("TranslateSBML:GUIInput:filename",
2599       "Failed to read filename");
2600   }
2601 
2602   /* get the filename returned */
2603   filename = readUnicodeStringFromArrays(mxFilename);
2604 
2605   mxDestroyArray(mxExt[0]);
2606   mxDestroyArray(mxFilename[1]);
2607   mxDestroyArray(mxFilename[0]);
2608 
2609   return filename;
2610 }
2611 
2612 ////////////////////////////////////////////////////////////////////////////
2613 //
2614 // Arguments.cpp
2615 
2616 /* determine whether we are in octave or matlab */
2617 unsigned int
determinePlatform()2618 determinePlatform()
2619 {
2620   unsigned int usingOctave = 0;
2621   mxArray * mxOctave[1];
2622 
2623   mexCallMATLAB(1, mxOctave, 0, NULL, "isoctave");
2624 
2625   size_t nBuflen = (mxGetM(mxOctave[0])*mxGetN(mxOctave[0])+1);
2626   char * pacTempString1 = (char *)(safe_calloc(nBuflen, sizeof(char)));
2627   int nStatus = mxGetString(mxOctave[0], pacTempString1, (mwSize)(nBuflen));
2628 
2629   if (nStatus != 0)
2630   {
2631     reportError("OutputSBML:platformDetection",
2632       "Could not determine platform");
2633   }
2634 
2635   safe_free(pacTempString1);
2636   mxDestroyArray(mxOctave[0]);
2637 
2638   return usingOctave;
2639 }
2640 
2641 bool
answerYesToQuestion(const std::string & question)2642 answerYesToQuestion(const std::string& question)
2643 {
2644   bool answer = false;
2645   mxArray *mxPrompt[2], *mxReply[1];
2646   char *pacReply;
2647   mxPrompt[0]= mxCreateString(question.c_str());
2648   mxPrompt[1]= mxCreateString("s");
2649   mexCallMATLAB(1, mxReply, 2, mxPrompt, "input");
2650   mxDestroyArray(mxPrompt[0]);
2651   mxDestroyArray(mxPrompt[1]);
2652 
2653   size_t nBufferLen = (mxGetM(mxReply[0])*mxGetN(mxReply[0])+1);
2654   pacReply = (char *) (safe_calloc(nBufferLen, sizeof(char)));
2655   mxGetString(mxReply[0], pacReply, (mwSize)(nBufferLen));
2656   mxDestroyArray(mxReply[0]);
2657 
2658   if (strcmp_insensitive(pacReply, "y") == 0)
2659   {
2660     answer = true;
2661   }
2662   safe_free(pacReply);
2663 
2664   return answer;
2665 }
2666 
2667 ///////////////////////////////////////////////////////////////////////////////
2668 //
2669 // functions used to check arguments for OutputSBML
2670 
2671 void
validateNumberOfInputsForOutput(int nrhs,const mxArray * prhs[],unsigned int usingOctave,unsigned int & outputVersion,int nlhs)2672 validateNumberOfInputsForOutput(int nrhs, const mxArray *prhs[],
2673   unsigned int usingOctave, unsigned int& outputVersion, int nlhs)
2674 {
2675   if (nlhs > 0 && nrhs == 0)
2676   {
2677     outputVersion = 1;
2678   }
2679   else
2680   {
2681     if (nrhs < 1)
2682     {
2683       reportError("OutputSBML:inputArgs",
2684         "Must supply at least the model as an input argument\n"
2685         "USAGE: OutputSBML(SBMLModel, (filename), (exclusiveFlag), (applyUserValidation), (fbcGeneProductOptions))");
2686     }
2687     if (usingOctave == 1 && nrhs < 2)
2688     {
2689       reportError("OutputSBML:Octave:needFilename",
2690         "Octave requires the filename to be specified\n"
2691         "USAGE: OutputSBML(SBMLModel, (filename), (exclusiveFlag), (applyUserValidation), (fbcGeneProductOptions))");
2692     }
2693     if (nrhs > 5)
2694     {
2695       reportError("OutputSBML:inputArguments", "Too many input arguments\n"
2696         "USAGE: OutputSBML(SBMLModel, (filename), (exclusiveFlag), (applyUserValidation), (fbcGeneProductOptions))");
2697     }
2698 
2699     if (nrhs > 1 && ((mxIsChar(prhs[1]) != 1) || (mxGetM(prhs[1]) != 1)))
2700     {
2701       reportError("OutputSBML:inputArguments:invalidFilename",
2702         "Second argument must be a filename\n"
2703         "USAGE: OutputSBML(SBMLModel, (filename), (exclusiveFlag), (applyUserValidation), (fbcGeneProductOptions))");
2704     }
2705     if (nrhs > 2 && !mxIsNumeric(prhs[2]))
2706     {
2707       reportError("OutputSBML:inputArguments:exclusiveFlag",
2708         "exclusiveFlag is an optional argument but must be a number\n"
2709         "USAGE: OutputSBML(SBMLModel, (filename), (exclusiveFlag), (applyUserValidation), (fbcGeneProductOptions))");
2710     }
2711 
2712     if (nrhs > 3 && !mxIsNumeric(prhs[3]))
2713     {
2714       reportError("OutputSBML:inputArguments:applyUserValidation",
2715         "applyUserValidation is an optional argument but must be a number\n"
2716         "USAGE: OutputSBML(SBMLModel, (filename), (exclusiveFlag), (applyUserValidation), (fbcGeneProductOptions))");
2717     }
2718 
2719     if (nrhs > 4 && (!mxIsNumeric(prhs[4]) || (mxGetM(prhs[4]) != 1) || (mxGetN(prhs[4]) != 2)))
2720     {
2721       reportError("OutputSBML:inputArguments:fbcGeneProductOptions",
2722         "fbcGeneProductOptions is an optional argument but must be an array with two numbers\n"
2723         "USAGE: OutputSBML(SBMLModel, (filename), (exclusiveFlag), (applyUserValidation), (fbcGeneProductOptions))");
2724     }
2725 
2726   }
2727 
2728 }
2729 
2730 void
validateNumberOfOutputsForOutput(int nlhs)2731 validateNumberOfOutputsForOutput(int nlhs)
2732 {
2733   if (nlhs > 0)
2734   {
2735     reportError("OutputSBML:outputArguments", "Too many output arguments\n"
2736       "USAGE: OutputSBML(SBMLModel, (filename), (exclusiveFlag))");
2737   }
2738 }
2739 
2740 void
populateModelArray(int nrhs,const mxArray * prhs[])2741 populateModelArray(int nrhs, const mxArray *prhs[])
2742 {
2743   modelArray = mxDuplicateArray(prhs[0]);
2744 
2745   /**
2746   * note second argument may be the filename
2747   *
2748   * we now have the option of a third argument that indicates that we
2749   * want the structure to ONLY contain expected fields or not
2750   *
2751   * and a fourth argument that tells us whether to apply user
2752   * specific validation
2753   *
2754   * and a fifth argument saying whether to use ids/lebels in fbc
2755   */
2756   if (nrhs > 4)
2757   {
2758     double *pr2 = mxGetPr(prhs[2]);
2759     if (*pr2 == 0)
2760     {
2761       onlyExpectedFields = false;
2762     }
2763     else
2764     {
2765       onlyExpectedFields = true;
2766     }
2767     double *pr3 = mxGetPr(prhs[3]);
2768     if (*pr3 == 0)
2769     {
2770       applyUserValidation = false;
2771     }
2772     else
2773     {
2774       applyUserValidation = true;
2775     }
2776     double *pr = mxGetPr(prhs[4]);
2777 
2778     if (*pr == 0)
2779     {
2780       fbcUsingId = false;
2781     }
2782     else
2783     {
2784       fbcUsingId = true;
2785     }
2786     pr++;
2787     if (*pr == 0)
2788     {
2789       fbcAddGeneProducts = false;
2790     }
2791     else
2792     {
2793       fbcAddGeneProducts = true;
2794     }
2795   }
2796   else if (nrhs > 3)
2797   {
2798     double *pr2 = mxGetPr(prhs[2]);
2799     if (*pr2 == 0)
2800     {
2801       onlyExpectedFields = false;
2802     }
2803     else
2804     {
2805       onlyExpectedFields = true;
2806     }
2807     double *pr3 = mxGetPr(prhs[3]);
2808     if (*pr3 == 0)
2809     {
2810       applyUserValidation = false;
2811     }
2812     else
2813     {
2814       applyUserValidation = true;
2815     }
2816     fbcUsingId = false;
2817     fbcAddGeneProducts = true;
2818   }
2819   else if ( nrhs > 2)
2820   {
2821     double *pr2 = mxGetPr(prhs[2]);
2822     if (*pr2 == 0)
2823     {
2824       onlyExpectedFields = false;
2825     }
2826     else
2827     {
2828       onlyExpectedFields = true;
2829     }
2830     applyUserValidation = false;
2831     fbcUsingId = false;
2832     fbcAddGeneProducts = true;
2833   }
2834   else
2835   {
2836     onlyExpectedFields = true;
2837     applyUserValidation = false;
2838     fbcUsingId = false;
2839     fbcAddGeneProducts = true;
2840   }
2841 
2842   // we have made memory - need to free it is we exit prematurely
2843   freeMemory = true;
2844 }
2845 
2846 void
validateModel()2847 validateModel()
2848 {
2849   mxArray * mxCheckStructure[2];
2850   mxArray * mxModel[3];
2851   mxModel[0] = modelArray;
2852   if (onlyExpectedFields)
2853   {
2854     mxModel[1] = mxCreateDoubleScalar(1);
2855   }
2856   else
2857   {
2858 
2859     mxModel[1] = mxCreateDoubleScalar(0);
2860   }
2861   if (applyUserValidation)
2862   {
2863     mxModel[2] = mxCreateDoubleScalar(1);
2864   }
2865   else
2866   {
2867 
2868     mxModel[2] = mxCreateDoubleScalar(0);
2869   }
2870   int nStatus = mexCallMATLAB(2, mxCheckStructure, 3, mxModel, "isSBML_Model");
2871 
2872   int value = (int)(mxGetScalar(mxCheckStructure[0]));
2873   if ((nStatus != 0) || (value != 1))
2874   {
2875     /* there are errors - use the pacTempString1 char * to list these to the user */
2876     size_t nBuflen = (mxGetM(mxCheckStructure[1])*mxGetN(mxCheckStructure[1])+1);
2877     char * pacTempString1 = (char *)safe_calloc(nBuflen, sizeof(char));
2878     nStatus = mxGetString(mxCheckStructure[1], pacTempString1, (mwSize)(nBuflen));
2879     std::ostringstream errMsg;
2880     if (nStatus == 0)
2881     {
2882       errMsg << "\nFirst input must be a valid MATLAB_SBML Structure\n\n" <<
2883         "Errors reported: " << pacTempString1 << "\nUSAGE: OutputSBML(SBMLModel"
2884         << ", (filename), (exclusiveFlag), (applyUserValidation))";
2885       reportError("OutputSBML:inputArguments:invalidModelSupplied", errMsg.str());
2886     }
2887     else
2888     {
2889       errMsg << "\nFirst input must be a valid MATLAB_SBML Structure\n\n" <<
2890         "\nUSAGE: OutputSBML(SBMLModel, (filename), (exclusiveFlag), (applyUserValidation))";
2891       reportError("OutputSBML:inputArguments:invalidStructureSupplied", errMsg.str());
2892     }
2893     safe_free(pacTempString1);
2894   }
2895 
2896   mxDestroyArray(mxCheckStructure[0]);
2897   mxDestroyArray(mxCheckStructure[1]);
2898 }
2899 
validateFilenameForOutput(int nrhs,const mxArray * prhs[])2900 FILE_CHAR validateFilenameForOutput(int nrhs, const mxArray *prhs[])
2901 {
2902   FILE_CHAR filename = NULL;
2903   if (nrhs >= 2)
2904   {
2905     if (mxIsChar(prhs[1]) != 1)
2906     {
2907       reportError("OutputSBML:inputArguments:invalidFilename",
2908         "Second input must be a filename\n"
2909         "USAGE: OutputSBML(SBMLModel, (filename), (exclusiveFlag))");
2910     }
2911 
2912     size_t nBuflen = (mxGetM(prhs[1])*mxGetN(prhs[1])+1);
2913     filename = readUnicodeString(prhs[1], (mwSize)nBuflen);
2914   }
2915   else
2916   {
2917     filename = browseForFilename();
2918   }
2919 
2920      /*
2921     * check that the extension has been used
2922     */
2923 #if USE_FILE_WCHAR
2924     if (wcsstr(filename, L".xml") == NULL)
2925     {
2926       wcscat(filename, L".xml");
2927     }
2928 #else
2929     /* check that the extension has been used  */
2930     if (strstr(filename, ".xml") == NULL)
2931     {
2932       strcat(filename, ".xml");
2933     }
2934 #endif
2935 
2936 
2937   return filename;
2938 }
2939 
2940 //////////////
2941 
2942 // functions for TranslatSBML
2943 void
validateNumberOfInputsForTranslate(int nrhs,const mxArray * prhs[],unsigned int usingOctave)2944 validateNumberOfInputsForTranslate(int nrhs, const mxArray *prhs[],
2945                                    unsigned int usingOctave)
2946 {
2947   if (nrhs > 4)
2948   {
2949     reportError("TranslateSBML:inputArguments", "Too many input arguments\n"
2950       "USAGE: [model, (errors), (version)] = "
2951       "TranslateSBML((filename), (validateFlag), (verboseFlag), (fbcGeneProductOptions))");
2952   }
2953 
2954   if (nrhs > 0 && ((mxIsChar(prhs[0]) != 1) || (mxGetM(prhs[0]) != 1)))
2955   {
2956     reportError("TranslateSBML:inputArguments:invalidFilename",
2957       "First argument must be a filename\n"
2958       "USAGE: [model, (errors), (version)] = "
2959       "TranslateSBML((filename), (validateFlag), (verboseFlag), (fbcGeneProductOptions))");
2960   }
2961   if (nrhs > 1 && !mxIsNumeric(prhs[1]))
2962   {
2963     reportError("TranslateSBML:inputArguments:validateFlag",
2964       "validateFlag is an optional argument but must be a number\n"
2965       "USAGE: [model, (errors), (version)] = "
2966       "TranslateSBML((filename), (validateFlag), (verboseFlag), (fbcGeneProductOptions))");
2967   }
2968 
2969   if (nrhs > 2 && !mxIsNumeric(prhs[2]))
2970   {
2971     reportError("TranslateSBML:inputArguments:verboseFlag",
2972       "verboseFlag is an optional argument but must be a number\n"
2973       "USAGE: [model, (errors), (version)] = "
2974       "TranslateSBML((filename), (validateFlag), (verboseFlag), (fbcGeneProductOptions))");
2975   }
2976 
2977   if (nrhs > 3 && (!mxIsNumeric(prhs[3]) || (mxGetM(prhs[3]) != 1) || (mxGetN(prhs[3]) != 2)))
2978   {
2979     reportError("TranslateSBML:inputArguments:fbcGeneProductOptions",
2980       "fbcGeneProductOptions is an optional argument but must be an array with two numbers\n"
2981       "USAGE: [model, (errors), (version)] = "
2982       "TranslateSBML((filename), (validateFlag), (verboseFlag), (fbcGeneProductOptions))");
2983   }
2984 
2985   if (usingOctave && nrhs == 0)
2986   {
2987     reportError("TranslateSBML:Octave:needFilename",
2988       "Octave requires the filename to be specified\n"
2989         "USAGE: [model, (errors), (version)] = "
2990         "TranslateSBML(filename, (validateFlag), (verboseFlag))");
2991   }
2992 }
2993 
2994 void
validateNumberOfOutputsForTranslate(int nlhs,mxArray * plhs[],unsigned int & outputErrors,unsigned int & outputVersion)2995 validateNumberOfOutputsForTranslate(int nlhs, mxArray *plhs[],
2996                                     unsigned int& outputErrors,
2997                                     unsigned int& outputVersion)
2998 {
2999   switch (nlhs)
3000   {
3001   case 3:
3002     outputErrors = 1;
3003     outputVersion = 1;
3004     break;
3005   case 2:
3006     outputErrors = 1;
3007     break;
3008   case 1:
3009   case 0:
3010     break;
3011   default:
3012     reportError("TranslateSBML:outputArguments", "Too many output arguments\n"
3013       "USAGE: [model, (errors), (version)] = "
3014       "TranslateSBML((filename), (validateFlag), (verboseFlag))");
3015     break;
3016   }
3017 }
3018 
3019 void
checkFileExists(FILE_CHAR filename)3020 checkFileExists(FILE_CHAR filename)
3021 {
3022     FILE *fp;
3023     fp = FILE_FOPEN(filename);
3024     if(fp == NULL)
3025     {
3026       char * msgTxt = NULL;
3027 #if USE_FILE_WCHAR
3028       msgTxt = (char *) safe_calloc(wcslen(filename)+35, sizeof(char));
3029       sprintf(msgTxt, "File %ws does not exist on this path", filename);
3030 #else
3031       msgTxt = (char *) safe_calloc(strlen(filename)+35, sizeof(char));
3032       sprintf(msgTxt, "File %s does not exist on this path", filename);
3033 #endif
3034       reportError("TranslateSBML:inputArguments:filename", msgTxt);
3035       safe_free(msgTxt);
3036     }
3037     else
3038     {
3039       fclose(fp);
3040     }
3041 
3042 }
3043 
3044 FILE_CHAR
getGivenFilename(const mxArray * prhs[])3045 getGivenFilename(const mxArray* prhs[])
3046 {
3047   FILE_CHAR filename = NULL;
3048   size_t nBufferLen  = mxGetNumberOfElements (prhs[0]) + 1;
3049   filename = readUnicodeString(prhs[0], nBufferLen);
3050 
3051   if (filename == NULL)
3052   {
3053     reportError("TranslateSBML:inputArguments:filename",
3054       "Failed to read filename");
3055   }
3056 
3057   checkFileExists(filename);
3058   return filename;
3059 }
3060 
3061 FILE_CHAR
getFilename(int nrhs,const mxArray * prhs[],unsigned int & validateFlag,unsigned int & verboseFlag)3062 getFilename(int nrhs, const mxArray* prhs[], unsigned int& validateFlag,
3063             unsigned int& verboseFlag)
3064 {
3065   FILE_CHAR filename = NULL;
3066 
3067   double *pr = 0;
3068   switch (nrhs)
3069   {
3070   case 4:
3071     // arg 3
3072     pr = mxGetPr(prhs[3]);
3073 
3074     if (*pr == 0)
3075     {
3076       fbcUsingId = false;
3077     }
3078     else
3079     {
3080       fbcUsingId = true;
3081     }
3082     pr++;
3083     if (*pr == 0)
3084     {
3085       fbcAddGeneProducts = false;
3086     }
3087     else
3088     {
3089       fbcAddGeneProducts = true;
3090     }
3091     // arg 2
3092     verboseFlag = (int)mxGetScalar(prhs[2]);
3093     // arg 1
3094     validateFlag = (int)mxGetScalar(prhs[1]);
3095     // arg 0
3096     filename = getGivenFilename(prhs);
3097     break;
3098   case 3:
3099     // arg 2
3100     verboseFlag = (int)mxGetScalar(prhs[2]);
3101     // arg 1
3102     validateFlag = (int)mxGetScalar(prhs[1]);
3103     // arg 0
3104     filename = getGivenFilename(prhs);
3105     break;
3106   case 2:
3107     // arg 1
3108     validateFlag = (int)mxGetScalar(prhs[1]);
3109     // arg 0
3110     filename = getGivenFilename(prhs);
3111     break;
3112   case 1:
3113     // arg 0
3114     filename = getGivenFilename(prhs);
3115     break;
3116   case 0:
3117     filename = browseForFilename();
3118     if (answerYesToQuestion("Do you want to validate the model? Enter y/n "))
3119     {
3120       validateFlag = 1;
3121     }
3122     fbcUsingId = false;
3123     fbcAddGeneProducts = true;
3124     break;
3125   default:
3126     break;
3127   }
3128   return filename;
3129 }
3130 
3131 ///////////////////////////////////////////////////////////////////////////
3132 
3133 // functions called by main functions
3134 FILE_CHAR
validateInputOutputForOutput(int nlhs,mxArray * plhs[],int nrhs,const mxArray * prhs[],unsigned int usingOctave,unsigned int & outputVersion)3135 validateInputOutputForOutput(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[],
3136                     unsigned int usingOctave, unsigned int& outputVersion)
3137 {
3138   FILE_CHAR filename = NULL;
3139   validateNumberOfInputsForOutput(nrhs, prhs, usingOctave, outputVersion, nlhs);
3140   if (outputVersion == 0)
3141   {
3142     validateNumberOfOutputsForOutput(nlhs);
3143 
3144     populateModelArray(nrhs, prhs);
3145     validateModel();
3146     filename = validateFilenameForOutput(nrhs, prhs);
3147   }
3148   return filename;
3149 }
3150 
3151 FILE_CHAR
validateInputOutputForTranslate(int nlhs,mxArray * plhs[],int nrhs,const mxArray * prhs[],unsigned int usingOctave,unsigned int & outputErrors,unsigned int & outputVersion,unsigned int & validateFlag,unsigned int & verboseFlag)3152 validateInputOutputForTranslate(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[],
3153                     unsigned int usingOctave, unsigned int& outputErrors,
3154                     unsigned int& outputVersion, unsigned int& validateFlag,
3155                     unsigned int& verboseFlag)
3156 {
3157   FILE_CHAR filename = NULL;
3158   validateNumberOfInputsForTranslate(nrhs, prhs, usingOctave);
3159   validateNumberOfOutputsForTranslate(nlhs, plhs, outputErrors, outputVersion);
3160   filename = getFilename(nrhs, prhs, validateFlag, verboseFlag);
3161 
3162   return filename;
3163 }
3164 
3165 
3166 void
OutputVersionInformation(mxArray * plhs[])3167 OutputVersionInformation(mxArray *plhs[])
3168 {
3169   const char *version_struct[] =
3170   {
3171     "libSBML_version",
3172     "libSBML_version_string",
3173     "XML_parser",
3174     "XML_parser_version",
3175     "isFBCEnabled",
3176     "packagesEnabled"
3177   };
3178 
3179   const char *xml_parsers[] =
3180   {
3181     "libxml2" ,
3182     "expat" ,
3183     "xerces",
3184     "not found"
3185   };
3186 
3187   mwSize dims[2] = {1, 1};
3188 
3189   const char * parser = xml_parsers[0];
3190   unsigned int i = 0;
3191 
3192 
3193   plhs[2] = mxCreateStructArray(2, dims, 6, version_struct);
3194 
3195   mxSetField(plhs[2], 0, "libSBML_version", CreateIntScalar(getLibSBMLVersion()));
3196   mxSetField(plhs[2], 0, "libSBML_version_string", mxCreateString(getLibSBMLDottedVersion()));
3197 
3198   while (isLibSBMLCompiledWith(parser) == 0 && i < 3)
3199   {
3200     ++i;
3201     parser = xml_parsers[i];
3202   }
3203 
3204   mxSetField(plhs[2], 0, "XML_parser", mxCreateString(parser));
3205   mxSetField(plhs[2], 0, "XML_parser_version", mxCreateString(getLibSBMLDependencyVersionOf(parser)));
3206 
3207 #ifdef USE_FBC
3208   mxSetField(plhs[2], 0, "isFBCEnabled", mxCreateString("enabled"));
3209 
3210 #else
3211   mxSetField(plhs[2], 0, "isFBCEnabled", mxCreateString("disabled"));
3212 
3213 #endif
3214   std::ostringstream oss;
3215   bool first = true;
3216   for (unsigned int i = 0; i < SBMLExtensionRegistry::getNumRegisteredPackages(); ++i)
3217   {
3218     std::string name = SBMLExtensionRegistry::getRegisteredPackageName(i);
3219     if (reqdPkgPrefixes.contains(name) || unreqdPkgPrefixes.contains(name))
3220     {
3221       if (!first)
3222       {
3223         oss << ";";
3224       }
3225       oss << name;
3226       first = false;
3227     }
3228   }
3229 
3230   std::string msg = oss.str();
3231   mxSetField(plhs[2], 0, "packagesEnabled", mxCreateString(msg.c_str()));
3232 }
3233 
3234 ////////////////////////////////////////////////////////////////////////////
3235 //
3236 // TranslateSBML.cpp
3237 SBMLDocument*
readSBMLDocument(FILE_CHAR filename)3238 readSBMLDocument(FILE_CHAR filename)
3239 {
3240   SBMLDocument* doc = NULL;
3241 #if USE_FILE_WCHAR
3242   if (endsWith(filename, ".xml") == 0)
3243   {
3244     StringBuffer_t *sb = NULL;
3245     unsigned long count = 0;
3246     char buffer[1024];
3247 
3248     FILE* fp = FILE_FOPEN(filename);
3249 
3250     sb = StringBuffer_create(1);
3251 
3252     while ((count = (unsigned long)fread(&buffer, sizeof(char), 1024, fp)) > 0)
3253     {
3254       StringBuffer_appendWithLength(sb,buffer, (unsigned long)count);
3255       memset(&buffer, 0, 1024*sizeof(char));
3256     }
3257     StringBuffer_appendChar(sb, 0);
3258 
3259     fclose(fp);
3260     doc = readSBMLFromString(StringBuffer_getBuffer(sb));
3261     StringBuffer_free(sb);
3262   }
3263   else
3264   {
3265     size_t len = wcslen(filename);
3266     char* file = (char*) mxCalloc(len+1, sizeof(char));
3267     wcstombs(file, filename, len);
3268     doc = readSBML(file);
3269     mxFree(file);
3270   }
3271 #else
3272   doc = readSBML(filename);
3273 #endif
3274 
3275   return doc;
3276 }
3277 
3278 void
OutputErrorInformation(mxArray * plhs[],SBMLDocument * doc)3279 OutputErrorInformation(mxArray *plhs[], SBMLDocument* doc)
3280 {
3281   const char *error_struct[] =
3282   {
3283     "line",
3284     "errorId",
3285     "severity",
3286     "message"
3287   };
3288 
3289   mwSize errordims[2];
3290 
3291   unsigned int totalerrors = doc->getNumErrors();
3292   errordims[0] = 1;
3293   errordims[1] = totalerrors;
3294   plhs[1] = mxCreateStructArray(2, errordims, 4, error_struct);
3295   for (unsigned int i = 0; i < totalerrors; ++i)
3296   {
3297     const XMLError* e = (const XMLError*)(doc->getError(i));
3298     mxSetField(plhs[1], i, "line", CreateIntScalar(e->getLine()));
3299     mxSetField(plhs[1], i, "errorId", CreateIntScalar(e->getErrorId()));
3300     mxSetField(plhs[1], i, "severity", mxCreateString(e->getSeverityAsString().c_str()));
3301     mxSetField(plhs[1], i, "message", mxCreateString(e->getMessage().c_str()));
3302   }
3303 }
3304 
3305 void
displayLine(const std::string & line)3306 displayLine(const std::string& line)
3307 {
3308   mxArray* mxErrors[1];
3309   mxErrors[0] = mxCreateString(line.c_str());
3310   mexCallMATLAB(0, NULL, 1, mxErrors, "disp");
3311   mxDestroyArray(mxErrors[0]);
3312 }
3313 
3314 void
displayErrors(SBMLDocument * doc,unsigned int warnings,unsigned int errors,unsigned int verboseFlag,unsigned int & listWarningsFlag)3315 displayErrors(SBMLDocument* doc, unsigned int warnings, unsigned int errors,
3316               unsigned int verboseFlag, unsigned int& listWarningsFlag)
3317 {
3318   std::ostringstream numErrs;
3319   numErrs << "The model contains " << errors << " errors";
3320   if (warnings > 0)
3321   {
3322     numErrs << " and " << warnings << " warnings";
3323   }
3324   numErrs << "." << std::endl;
3325 
3326   displayLine(numErrs.str());
3327 
3328   if (verboseFlag == 1 && warnings > 0)
3329   {
3330     if (!answerYesToQuestion("Do you want to exclude the warnings from the list? Enter y/n ") )
3331     {
3332       listWarningsFlag = 1;
3333     }
3334   }
3335 
3336   if (verboseFlag == 1)
3337   {
3338     numErrs.str("");
3339     numErrs.clear();
3340     numErrs << "************************************************************"
3341       << std::endl << "Line ErrorId Severity Message" << std::endl;
3342 
3343     displayLine(numErrs.str());
3344 
3345     for (unsigned int i = 0; i < doc->getNumErrors(); ++i)
3346     {
3347       const XMLError* e = (const XMLError_t *) doc->getError(i);
3348 
3349       if (listWarningsFlag == 1 || e->getSeverity() > 1)
3350       {
3351         numErrs.str("");
3352         numErrs.clear();
3353         numErrs << e->getLine() << ": (" << e->getErrorId() << ")  "
3354           << e->getSeverityAsString() << " " << e->getMessage() << std::endl;
3355 
3356         displayLine(numErrs.str());
3357       }
3358     }
3359 
3360   }
3361 }
3362 
3363 unsigned int
validateDocument(SBMLDocument * doc,unsigned int validateFlag,unsigned int verboseFlag,unsigned int & errors,unsigned int & warnings)3364 validateDocument(SBMLDocument* doc, unsigned int validateFlag, unsigned int verboseFlag,
3365                  unsigned int& errors, unsigned int& warnings)
3366 {
3367   /* check for errors at read */
3368   unsigned int totalerrors = doc->getNumErrors();
3369 
3370   if (validateFlag > 0)
3371   {
3372     if (verboseFlag > 0 && totalerrors > 0)
3373     {
3374       if (!answerYesToQuestion("There are errors found during reading. Do you want to continue validation? Enter y/n "))
3375       {
3376         totalerrors += doc->checkConsistency();
3377       }
3378     }
3379     else
3380     {
3381       totalerrors += doc->checkConsistency();
3382     }
3383   }
3384 
3385   /* divide the totalerrors into errors
3386   * and warnings
3387   */
3388   for (unsigned int i = 0; i < totalerrors; ++i)
3389   {
3390     const XMLError * e = (const XMLError *) doc->getError(i);
3391     if (e->getSeverity() < 2)
3392     {
3393       warnings = warnings + 1;
3394     }
3395   }
3396   errors = totalerrors - warnings;
3397 
3398   return totalerrors;
3399 }
3400 
3401 
3402 ///////////////////////////////////////////////////////////////////////////////
3403 /**
3404  * NAME:    mexFunction
3405  *
3406  * PARAMETERS:  int     nlhs     -  number of output arguments
3407  *              mxArray *plhs[]  -  output arguments
3408  *              int     nrhs     -  number of input arguments
3409  *              mxArray *prhs[]  -  input arguments
3410  *
3411  * RETURNS:
3412  *
3413  * FUNCTION:  MATLAB standard dll export function
3414  *            any returns are made through the mxArray * prhs
3415  */
3416 void
mexFunction(int nlhs,mxArray * plhs[],int nrhs,const mxArray * prhs[])3417 mexFunction (int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
3418 {
3419   // we have not made persistent memory
3420   freeMemory = false;
3421   std::ostringstream numErrs;
3422   /* determine whether we are in octave or matlab */
3423   unsigned int usingOctave = determinePlatform();
3424 
3425   /* flags for determining what to output and whether to validate */
3426   unsigned int outputErrors = 0;
3427   unsigned int outputVersion = 0;
3428   unsigned int validateFlag = 0;
3429   unsigned int verboseFlag = 1;
3430   unsigned int listWarningsFlag = 0;
3431   bool readModel = true;
3432 
3433   FILE_CHAR pacFilename = validateInputOutputForTranslate(nlhs, plhs, nrhs, prhs, usingOctave, outputErrors,
3434     outputVersion, validateFlag, verboseFlag);
3435 
3436   SBMLDocument* sbmlDocument = readSBMLDocument(pacFilename);
3437 
3438   if (sbmlDocument->getModel() == NULL)
3439   {
3440    /* at this point - if there have been fatal errors
3441     * dont try anything else
3442     */
3443     readModel = false;
3444   }
3445   else
3446   {
3447     ///* check for errors at read */
3448     unsigned int errors = 0, warnings = 0;
3449     unsigned int totalerrors = validateDocument(sbmlDocument, validateFlag, verboseFlag, errors, warnings);
3450 
3451    ///*if errors occur report these - promt user as to whether to import the Model*/
3452     if (totalerrors != 0)
3453     {
3454       displayErrors(sbmlDocument, warnings, errors, verboseFlag, listWarningsFlag);
3455 
3456       if (!(errors == 0 && listWarningsFlag == 0))
3457       {
3458         if (validateFlag == 0)
3459         {
3460           numErrs.str("");
3461           numErrs.clear();
3462           numErrs << "Error encountered during read." << std::endl;
3463           displayLine(numErrs.str());
3464         }
3465         else
3466         {
3467           if (verboseFlag == 1)
3468           {
3469             if (!answerYesToQuestion("Do you want to load the model anyway? Enter y/n "))
3470             {
3471               readModel = false;
3472             }
3473           }
3474         }
3475       }
3476     }
3477   }
3478   // output required structures
3479   if (outputVersion == 1)
3480   {
3481     OutputVersionInformation(plhs);
3482   }
3483 
3484   if (outputErrors == 1)
3485   {
3486     OutputErrorInformation(plhs, sbmlDocument);
3487   }
3488 
3489   if (readModel)
3490   {
3491     Model * sbmlModel = sbmlDocument->getModel();
3492     details = new ModelDetails(sbmlDocument);
3493     populatePackageLists();
3494 
3495     std::string tc = "model";
3496     const std::string func = "TranslateSBML";
3497     StructureFields *sf = new StructureFields(tc);
3498     sf->createStructure(func, sbmlDocument);
3499 
3500 //    plhs[0] = sf->getStructure();
3501     mxArray* mxArgs[3];
3502     mxArgs[0] = mxDuplicateArray(sf->getStructure());
3503     mxArgs[1] = CreateIntScalar(sbmlDocument->getLevel());
3504     mxArgs[2] = CreateIntScalar(sbmlDocument->getVersion());
3505     mexCallMATLAB(0, &plhs[0], 3, mxArgs, "addLevelVersion");
3506     mxDestroyArray(mxArgs[0]);
3507     mxDestroyArray(mxArgs[1]);
3508     mxDestroyArray(mxArgs[2]);
3509     delete details;
3510     delete sf;
3511   }
3512   else
3513   {
3514     /* we havent read in a Model */
3515     numErrs.str("");
3516     numErrs.clear();
3517     numErrs << "No model returned." << std::endl;
3518     displayLine(numErrs.str());
3519 
3520     plhs[0] = mxCreateStructArray(0, 0, 0, NULL);
3521   }
3522 }
3523 
3524 
3525