1 /**
2  * @cond doxygenLibsbmlInternal
3  *
4  * @file    XMLOutputStream.cpp
5  * @brief   XMLOutputStream
6  * @author  Ben Bornstein
7  *
8  * <!--------------------------------------------------------------------------
9  * This file is part of libSBML.  Please visit http://sbml.org for more
10  * information about SBML, and the latest version of libSBML.
11  *
12  * Copyright (C) 2020 jointly by the following organizations:
13  *     1. California Institute of Technology, Pasadena, CA, USA
14  *     2. University of Heidelberg, Heidelberg, Germany
15  *     3. University College London, London, UK
16  *
17  * Copyright (C) 2019 jointly by the following organizations:
18  *     1. California Institute of Technology, Pasadena, CA, USA
19  *     2. University of Heidelberg, Heidelberg, Germany
20  *
21  * Copyright (C) 2013-2018 jointly by the following organizations:
22  *     1. California Institute of Technology, Pasadena, CA, USA
23  *     2. EMBL European Bioinformatics Institute (EMBL-EBI), Hinxton, UK
24  *     3. University of Heidelberg, Heidelberg, Germany
25  *
26  * Copyright (C) 2009-2013 jointly by the following organizations:
27  *     1. California Institute of Technology, Pasadena, CA, USA
28  *     2. EMBL European Bioinformatics Institute (EMBL-EBI), Hinxton, UK
29  *
30  * Copyright (C) 2006-2008 by the California Institute of Technology,
31  *     Pasadena, CA, USA
32  *
33  * Copyright (C) 2002-2005 jointly by the following organizations:
34  *     1. California Institute of Technology, Pasadena, CA, USA
35  *     2. Japan Science and Technology Agency, Japan
36  *
37  * This library is free software; you can redistribute it and/or modify it
38  * under the terms of the GNU Lesser General Public License as published by
39  * the Free Software Foundation.  A copy of the license agreement is provided
40  * in the file named "LICENSE.txt" included with this software distribution and
41  * also available online as http://sbml.org/software/libsbml/license.html
42  * ---------------------------------------------------------------------- -->*/
43 
44 #include <iostream>
45 #include <sstream>
46 #include <fstream>
47 
48 #include <cstdio>
49 #include <sbml/xml/XMLTriple.h>
50 #include <sbml/xml/XMLOutputStream.h>
51 #include <sbml/xml/XMLAttributes.h>
52 #include <sbml/xml/XMLConstructorException.h>
53 #include <sbml/util/util.h>
54 #include <sbml/common/common.h>
55 #include <sbml/common/libsbml-version.h>
56 #include <sbml/SBMLNamespaces.h>
57 #if defined CYGWIN
58 #include <string.h>
59 #endif
60 
61 using namespace std;
62 
63 LIBSBML_CPP_NAMESPACE_BEGIN
64 #ifdef __cplusplus
65 
66 /**
67  * Checks if the given string has a character reference at index in the string.
68  *
69  * character reference is expressed as follows:
70  *
71  *  CharRef ::=  '&#' [0-9]+ ';' | '&#x' [0-9a-fA-F]+ ';'
72  *
73  * This function is internal implementation.
74  */
hasCharacterReference(const std::string & chars,size_t index)75 bool hasCharacterReference(const std::string &chars, size_t index)
76 {
77   const std::string decChars = "0123456789";
78   const std::string hexChars = "0123456789abcdefABCDEF";
79 
80   if ((chars.length() - 1) <= index)
81   {
82     return false;
83   }
84   else if (chars.at(index) != '&')
85   {
86     return false;
87   }
88   else if (chars.at(index+1) != '#')
89   {
90     return false;
91   }
92   else if (chars.at(index+2) == 'x')
93   {
94     //
95     // the character reference uses hex characters (e.g. &#x00A8; ) if any
96     //
97     size_t pos = chars.find_first_not_of(hexChars, index+3);
98 
99     if (pos == std::string::npos)
100     {
101       // ';' is not found
102       return false;
103     }
104     else if (pos < index + 4)
105     {
106       // hex characters are not found
107       return false;
108     }
109     else if (chars.at(pos) != ';')
110     {
111       // ';' is not found immediately after hex characters
112       return false;
113     }
114   }
115   else
116   {
117     //
118     // the character reference uses deciaml characters (e.g. &#0185; ) if any
119     //
120     size_t pos = chars.find_first_not_of(decChars, index+2);
121 
122     if (pos == std::string::npos)
123     {
124       // ';' is not found
125       return false;
126     }
127     else if (pos < index + 3)
128     {
129       // decimal characters are not found
130       return false;
131     }
132     else if (chars.at(pos) != ';')
133     {
134       // ';' is not found immediately after decimal characters
135       return false;
136     }
137   }
138 
139   return true;
140 }
141 
142 
143 /**
144  * Checks if the given string has a predefined entity at index in the string.
145  *
146  * predefined entities are expressed as follows:
147  *
148  *  1) &amp;
149  *  2) &apos;
150  *  3) &lt;
151  *  4) &gt;
152  *  5) &quot;
153  *
154  * This function is internal implementation.
155  */
hasPredefinedEntity(const std::string & chars,size_t index)156 bool hasPredefinedEntity(const std::string &chars, size_t index)
157 {
158   if ((chars.length() - 1) <= index)
159   {
160     return false;
161   }
162 
163   if (chars.find("&amp;",index) == index)
164   {
165     return true;
166   }
167   else if (chars.find("&apos;",index) == index)
168   {
169     return true;
170   }
171   else if (chars.find("&lt;",index) == index)
172   {
173     return true;
174   }
175   else if (chars.find("&gt;",index) == index)
176   {
177     return true;
178   }
179   else if (chars.find("&quot;",index) == index)
180   {
181     return true;
182   }
183 
184   return false;
185 }
186 
187 
188 // boolean indicating whether the comment on the top of the file is
189 // written (enabled by default)
190 bool XMLOutputStream::mWriteComment = true;
191 
192 // boolean indicating whether a timestamp will be generated at the time
193 // of writing (enabled by default)
194 bool XMLOutputStream::mWriteTimestamp = true;
195 
196 // the name of the library writing the file (i.e: libSBML)
197 std::string XMLOutputStream::mLibraryName = "libSBML";
198 
199 // the version of the library writing the file
200 std::string XMLOutputStream::mLibraryVersion = getLibSBMLDottedVersion();
201 
202 
203 /**
204  * Copy Constructor, made private so as to notify users, that copying an input stream is not supported.
205  */
XMLOutputStream(const XMLOutputStream & other)206 XMLOutputStream::XMLOutputStream (const XMLOutputStream& other)
207   : mStream(other.mStream)
208   , mEncoding(other.mEncoding)
209   , mInStart (other.mInStart)
210   , mDoIndent(other.mDoIndent)
211   , mIndent(other.mIndent)
212   , mInText(other.mInText)
213   , mSkipNextIndent(other.mSkipNextIndent)
214   , mNextAmpersandIsRef(other.mNextAmpersandIsRef)
215   , mStringStream(other.mStringStream)
216 {
217 }
218 
219 
220 /**
221  * Assignment operator, made private so as to notify users, that copying an input stream is not supported.
222  */
operator =(const XMLOutputStream &)223 XMLOutputStream& XMLOutputStream::operator=(const XMLOutputStream& /*other*/)
224 {
225   return *this;
226 }
227 
228 
229 /*
230  * Creates a new XMLOutputStream that wraps stream.
231  */
XMLOutputStream(std::ostream & stream,const std::string encoding,bool writeXMLDecl,const std::string programName,const std::string programVersion)232 XMLOutputStream::XMLOutputStream (  std::ostream&       stream
233                                   , const std::string  encoding
234                                   , bool                writeXMLDecl
235                                   , const std::string  programName
236                                   , const std::string  programVersion) :
237    mStream  ( stream   )
238  , mEncoding( encoding )
239  , mInStart ( false    )
240  , mDoIndent( true     )
241  , mIndent  ( 0        )
242  , mInText  ( false    )
243  , mSkipNextIndent ( false    )
244  , mNextAmpersandIsRef( false )
245  , mSBMLns (NULL)
246 {
247 
248   unsetStringStream();
249   mStream.imbue( locale::classic() );
250   if (writeXMLDecl) this->writeXMLDecl();
251   if (mWriteComment) this->writeComment(programName, programVersion, mWriteTimestamp);
252 }
253 
254 
255 /*
256  * Writes the given XML end element name to this XMLOutputStream.
257  */
258 void
endElement(const std::string & name,const std::string prefix)259 XMLOutputStream::endElement (const std::string& name, const std::string prefix)
260 {
261 
262   if (mInStart)
263   {
264     mInStart = false;
265     mStream << '/' << '>';
266   }
267   else if (mInText)
268   {
269     mInText = false;
270     mSkipNextIndent = false;
271     mStream << '<' << '/';
272     writeName(name, prefix);
273     mStream << '>';
274   }
275   else
276   {
277     downIndent();
278     writeIndent(true);
279 
280     mStream << '<' << '/';
281     writeName(name, prefix);
282     mStream << '>';
283   }
284 }
285 
286 
287 /*
288  * Writes the given XML end element 'prefix:name' to this
289  * XMLOutputStream.
290  */
291 void
endElement(const XMLTriple & triple,bool text)292 XMLOutputStream::endElement (const XMLTriple& triple, bool text)
293 {
294 
295   if (mInStart)
296   {
297     mInStart = false;
298     mStream << '/' << '>';
299   }
300   else if (mInText || text)
301   {
302     mInText = false;
303     mSkipNextIndent = false;
304     mStream << '<' << '/';
305     writeName(triple);
306     mStream << '>';
307   }
308   else
309   {
310     downIndent();
311     writeIndent(true);
312 
313     mStream << '<' << '/';
314     writeName(triple);
315     mStream << '>';
316   }
317 }
318 
319 
320 /*
321  * Turns automatic indentation on or off for this XMLOutputStream.
322  */
323 void
setAutoIndent(bool indent)324 XMLOutputStream::setAutoIndent (bool indent)
325 {
326   mDoIndent = indent;
327 }
328 
329 
330 /*
331  * Writes the given XML start element name to this XMLOutputStream.
332  */
333 void
startElement(const std::string & name,const std::string prefix)334 XMLOutputStream::startElement (const std::string& name, const std::string prefix)
335 {
336 
337   if (mInStart)
338   {
339     mStream << '>';
340     upIndent();
341   }
342 
343   mInStart = true;
344 
345   if (mInText && mSkipNextIndent)
346   {
347     mSkipNextIndent = false;
348   }
349   else
350   {
351     writeIndent();
352   }
353 
354   mStream << '<';
355   writeName(name, prefix);
356 }
357 
358 
359 /*
360  * Writes the given XML start element 'prefix:name' to this
361  * XMLOutputStream.
362  */
363 void
startElement(const XMLTriple & triple)364 XMLOutputStream::startElement (const XMLTriple& triple)
365 {
366 
367   if (mInStart)
368   {
369     mStream << '>';
370     upIndent();
371   }
372 
373   mInStart = true;
374 
375   if (mInText && mSkipNextIndent)
376   {
377     mSkipNextIndent = false;
378   }
379   else
380   {
381     writeIndent();
382   }
383 
384   mStream << '<';
385   writeName(triple);
386 }
387 
388 
389 /*
390  * Writes the given XML start and end element name to this XMLOutputStream.
391  */
392 void
startEndElement(const std::string & name,const std::string prefix)393 XMLOutputStream::startEndElement (const std::string& name, const std::string prefix)
394 {
395 
396   if (mInStart)
397   {
398     mStream << '>';
399     upIndent();
400   }
401 
402   if (mSkipNextIndent)
403     mSkipNextIndent = false;
404 
405   mInStart = false;
406 
407   if (mInText && mSkipNextIndent)
408   {
409     mSkipNextIndent = false;
410   }
411   else
412   {
413     writeIndent();
414   }
415 
416   mStream << '<';
417   writeName(name, prefix);
418   mStream << '/' << '>';
419 }
420 
421 
422 /*
423  * Writes the given XML start and end element 'prefix:name' to this
424  * XMLOutputStream.
425  */
426 void
startEndElement(const XMLTriple & triple)427 XMLOutputStream::startEndElement (const XMLTriple& triple)
428 {
429 
430   if (mInStart)
431   {
432     mStream << '>';
433     upIndent();
434   }
435 
436   if (mSkipNextIndent)
437     mSkipNextIndent = false;
438 
439   mInStart = false;
440 
441   if (mInText && mSkipNextIndent)
442   {
443     mSkipNextIndent = false;
444   }
445   else
446   {
447     writeIndent();
448   }
449 
450   mStream << '<';
451   writeName(triple);
452   mStream << '/' << '>';
453 }
454 
455 
456 /*
457  * Writes the given attribute, name="value" to this XMLOutputStream.
458  */
459 void
writeAttribute(const std::string & name,const std::string & value)460 XMLOutputStream::writeAttribute (const std::string& name, const std::string& value)
461 {
462   if ( value.empty() ) return;
463 
464   mStream << ' ';
465 
466   writeName ( name  );
467   writeValue( value );
468 }
469 
470 
471 /*
472  * Writes the given attribute, prefix:name="value" to this XMLOutputStream.
473  */
474 void
writeAttribute(const std::string & name,const std::string & prefix,const std::string & value)475 XMLOutputStream::writeAttribute (const std::string& name, const std::string& prefix, const std::string& value)
476 {
477   if ( value.empty() ) return;
478 
479   mStream << ' ';
480 
481   writeName ( name , prefix );
482   writeValue( value );
483 }
484 
485 
486 /*
487  * Writes the given attribute, prefix:name="value" to this
488  * XMLOutputStream.
489  */
490 void
writeAttribute(const XMLTriple & triple,const std::string & value)491 XMLOutputStream::writeAttribute (const XMLTriple& triple, const std::string& value)
492 {
493   mStream << ' ';
494 
495   writeName ( triple );
496   writeValue( value  );
497 }
498 
499 
500 /*
501  * Writes the given attribute, name="value" to this XMLOutputStream.
502  */
503 void
writeAttribute(const std::string & name,const char * value)504 XMLOutputStream::writeAttribute (const std::string& name, const char* value)
505 {
506   if ( !value || strcmp(value,"") == 0) return;
507 
508   mStream << ' ';
509 
510   writeName ( name  );
511   writeValue( value );
512 }
513 
514 
515 /*
516  * Writes the given attribute, prefix:name="value" to this XMLOutputStream.
517  */
518 void
writeAttribute(const std::string & name,const std::string & prefix,const char * value)519 XMLOutputStream::writeAttribute (const std::string& name, const std::string& prefix, const char* value)
520 {
521   if ( !value || strcmp(value,"") == 0) return;
522 
523   mStream << ' ';
524 
525   writeName ( name , prefix );
526   writeValue( value );
527 }
528 
529 
530 /*
531  * Writes the given attribute, prefix:name="value" to this
532  * XMLOutputStream.
533  */
534 void
writeAttribute(const XMLTriple & triple,const char * value)535 XMLOutputStream::writeAttribute (const XMLTriple& triple, const char* value)
536 {
537   if ( !value || strcmp(value,"") == 0) return;
538 
539   mStream << ' ';
540 
541   writeName ( triple );
542   writeValue( value  );
543 }
544 
545 
546 /*
547  * Writes the given attribute, name="true" or name="false" to this
548  * XMLOutputStream.
549  */
550 void
writeAttribute(const std::string & name,const bool & value)551 XMLOutputStream::writeAttribute (const std::string& name, const bool& value)
552 {
553 
554   mStream << ' ';
555 
556   writeName ( name  );
557   writeValue( value );
558 }
559 
560 
561 /*
562  * Writes the given attribute, prefix:name="true" or prefix:name="false" to this
563  * XMLOutputStream.
564  */
565 void
writeAttribute(const std::string & name,const std::string & prefix,const bool & value)566 XMLOutputStream::writeAttribute (const std::string& name, const std::string& prefix, const bool& value)
567 {
568   mStream << ' ';
569 
570   writeName ( name , prefix );
571   writeValue( value );
572 }
573 
574 
575 /*
576  * Writes the given attribute, prefix:name="true" or prefix:name="false" to
577  * this XMLOutputStream.
578  */
579 void
writeAttribute(const XMLTriple & triple,const bool & value)580 XMLOutputStream::writeAttribute (const XMLTriple& triple, const bool& value)
581 {
582 
583   mStream << ' ';
584 
585   writeName ( triple );
586   writeValue( value  );
587 }
588 
589 
590 /*
591  * Writes the given attribute, name="value" to this XMLOutputStream.
592  */
593 void
writeAttribute(const std::string & name,const double & value)594 XMLOutputStream::writeAttribute (const std::string& name, const double& value)
595 {
596 
597   mStream << ' ';
598 
599   writeName ( name  );
600   writeValue( value );
601 }
602 
603 
604 /*
605  * Writes the given attribute, prefix:name="value" to this XMLOutputStream.
606  */
607 void
writeAttribute(const std::string & name,const std::string & prefix,const double & value)608 XMLOutputStream::writeAttribute (const std::string& name, const std::string& prefix, const double& value)
609 {
610   mStream << ' ';
611 
612   writeName ( name , prefix );
613   writeValue( value );
614 }
615 
616 
617 /*
618  * Writes the given attribute, prefix:name="value" to this XMLOutputStream.
619  */
620 void
writeAttribute(const XMLTriple & triple,const double & value)621 XMLOutputStream::writeAttribute (const XMLTriple& triple, const double& value)
622 {
623   mStream << ' ';
624 
625   writeName ( triple );
626   writeValue( value  );
627 }
628 
629 
630 /*
631  * Writes the given attribute, name="value" to this XMLOutputStream.
632  */
633 void
writeAttribute(const std::string & name,const long & value)634 XMLOutputStream::writeAttribute (const std::string& name, const long& value)
635 {
636 
637   mStream << ' ';
638 
639   writeName ( name  );
640   writeValue( value );
641 }
642 
643 
644 /*
645  * Writes the given attribute, prefix:name="value" to this XMLOutputStream.
646  */
647 void
writeAttribute(const std::string & name,const std::string & prefix,const long & value)648 XMLOutputStream::writeAttribute (const std::string& name, const std::string& prefix, const long& value)
649 {
650   mStream << ' ';
651 
652   writeName ( name , prefix );
653   writeValue( value );
654 }
655 
656 
657 
658 /*
659  * Writes the given attribute, prefix:name="value" to this XMLOutputStream.
660  */
661 void
writeAttribute(const XMLTriple & triple,const long & value)662 XMLOutputStream::writeAttribute (const XMLTriple& triple, const long& value)
663 {
664   mStream << ' ';
665 
666   writeName ( triple );
667   writeValue( value  );
668 }
669 
670 
671 /*
672  * Writes the given attribute, name="value" to this XMLOutputStream.
673  */
674 void
writeAttribute(const std::string & name,const int & value)675 XMLOutputStream::writeAttribute (const std::string& name, const int& value)
676 {
677 
678   mStream << ' ';
679 
680   writeName ( name  );
681   writeValue( value );
682 }
683 
684 
685 /*
686  * Writes the given attribute, prefix:name="value" to this XMLOutputStream.
687  */
688 void
writeAttribute(const std::string & name,const std::string & prefix,const int & value)689 XMLOutputStream::writeAttribute (const std::string& name, const std::string& prefix, const int& value)
690 {
691   mStream << ' ';
692 
693   writeName ( name , prefix );
694   writeValue( value );
695 }
696 
697 
698 /*
699  * Writes the given attribute, prefix:name="value" to this
700  * XMLOutputStream.
701  */
702 void
writeAttribute(const XMLTriple & triple,const int & value)703 XMLOutputStream::writeAttribute (const XMLTriple& triple, const int& value)
704 {
705 
706   mStream << ' ';
707 
708   writeName ( triple );
709   writeValue( value  );
710 }
711 
712 
713 /*
714  * Writes the given attribute, name="value" to this XMLOutputStream.
715  */
716 void
writeAttribute(const std::string & name,const unsigned int & value)717 XMLOutputStream::writeAttribute (const std::string& name, const unsigned int& value)
718 {
719 
720   mStream << ' ';
721 
722   writeName ( name  );
723   writeValue( value );
724 }
725 
726 
727 /*
728  * Writes the given attribute, prefix:name="value" to this XMLOutputStream.
729  */
730 void
writeAttribute(const std::string & name,const std::string & prefix,const unsigned int & value)731 XMLOutputStream::writeAttribute (const std::string& name, const std::string& prefix, const unsigned int& value)
732 {
733   mStream << ' ';
734 
735   writeName ( name , prefix );
736   writeValue( value );
737 }
738 
739 
740 /*
741  * Writes the given attribute, prefix:name="value" to this
742  * XMLOutputStream.
743  */
744 void
writeAttribute(const XMLTriple & triple,const unsigned int & value)745 XMLOutputStream::writeAttribute (  const XMLTriple&     triple
746                                  , const unsigned int&  value )
747 {
748 
749   mStream << ' ';
750 
751   writeName ( triple );
752   writeValue( value  );
753 }
754 
755 
756 /*
757  * Decreases the indentation level for this XMLOutputStream.
758  */
759 void
downIndent()760 XMLOutputStream::downIndent ()
761 {
762   if (mDoIndent && mIndent) --mIndent;
763 }
764 
765 
766 /*
767  * Increases the indentation level for this XMLOutputStream.
768  */
769 void
upIndent()770 XMLOutputStream::upIndent ()
771 {
772   if (mDoIndent) ++mIndent;
773 }
774 
getStringStream()775 bool XMLOutputStream::getStringStream()
776 {
777   return mStringStream;
778 }
779 
780 
781 /*
782  * Outputs indentation whitespace.
783  */
784 void
writeIndent(bool isEnd)785 XMLOutputStream::writeIndent (bool isEnd)
786 {
787   if (mDoIndent)
788   {
789     if (mIndent > 0 || isEnd) mStream << endl;
790     for (unsigned int n = 0; n < mIndent; ++n) mStream << ' ' << ' ';
791   }
792 }
793 
794 
795 /*
796  * Outputs the given characters to the underlying stream.
797  */
798 void
writeChars(const std::string & chars)799 XMLOutputStream::writeChars (const std::string& chars)
800 {
801   for (size_t i=0; i < chars.length(); i++)
802   {
803     const char& c = chars.at(i);
804     if ( c == '&' &&
805         (LIBSBML_CPP_NAMESPACE ::hasCharacterReference(chars, i) ||
806          LIBSBML_CPP_NAMESPACE ::hasPredefinedEntity(chars,i)) )
807       mNextAmpersandIsRef = true;
808 
809     *this << c;
810   }
811 }
812 
813 
814 /*
815  * Outputs name.
816  */
817 void
writeName(const std::string & name,const std::string prefix)818 XMLOutputStream::writeName (const std::string& name, const std::string prefix)
819 {
820   if ( !prefix.empty() )
821   {
822     writeChars( prefix );
823     mStream << ':';
824   }
825 
826   writeChars(name);
827 }
828 
829 
830 /*
831  * Outputs prefix:name.
832  */
833 void
writeName(const XMLTriple & triple)834 XMLOutputStream::writeName (const XMLTriple& triple)
835 {
836   if ( !triple.getPrefix().empty() )
837   {
838     writeChars( triple.getPrefix() );
839     mStream << ':';
840   }
841 
842   writeChars( triple.getName() );
843 }
844 
845 
846 /*
847  * Outputs value in quotes.
848  */
849 void
writeValue(const std::string & value)850 XMLOutputStream::writeValue (const std::string& value)
851 {
852   mStream << '=' << '"';
853   writeChars(value);
854   mStream << '"';
855 }
856 
857 /*
858  * Outputs value in quotes.
859  */
860 void
writeValue(const char * value)861 XMLOutputStream::writeValue (const char* value)
862 {
863   mStream << '=' << '"';
864   writeChars(value);
865   mStream << '"';
866 }
867 
868 
869 /*
870  * Outputs "true" or "false" in quotes.
871  */
872 void
writeValue(const bool & value)873 XMLOutputStream::writeValue (const bool& value)
874 {
875   mStream << '=' << '"' << (value ? "true" : "false") << '"';
876 }
877 
878 
879 /*
880  * Outputs the double value in quotes, or "INF", "-INF", or "NaN".
881  */
882 void
writeValue(const double & value)883 XMLOutputStream::writeValue (const double& value)
884 {
885   mStream << '=' << '"';
886 
887   if (value != value)
888   {
889     mStream << "NaN";
890   }
891   else if (value == numeric_limits<double>::infinity())
892   {
893     mStream << "INF";
894   }
895   else if (value == - numeric_limits<double>::infinity())
896   {
897     mStream << "-INF";
898   }
899   else
900   {
901     mStream.precision(LIBSBML_DOUBLE_PRECISION);
902     mStream <<   value;
903   }
904 
905   mStream << '"';
906 }
907 
908 
909 /*
910  * Outputs the long value in quotes.
911  */
912 void
writeValue(const long & value)913 XMLOutputStream::writeValue (const long& value)
914 {
915   mStream << '=' << '"' << value << '"';
916 }
917 
918 
919 /*
920  * Outputs the int value in quotes.
921  */
922 void
writeValue(const int & value)923 XMLOutputStream::writeValue (const int& value)
924 {
925   mStream << '=' << '"' << value << '"';
926 }
927 
928 
929 /*
930  * Outputs the int value in quotes.
931  */
932 void
writeValue(const unsigned int & value)933 XMLOutputStream::writeValue (const unsigned int& value)
934 {
935   mStream << '=' << '"' << value << '"';
936 }
937 
938 void
setStringStream()939 XMLOutputStream::setStringStream()
940 {
941     mStringStream = true;
942 }
943 
944 void
unsetStringStream()945 XMLOutputStream::unsetStringStream()
946 {
947     mStringStream = false;
948 }
949 
950 
951 /*
952  * Writes the XML declaration:
953  * <?xml version="1.0" encoding="..."?>
954  */
955 void
writeXMLDecl()956 XMLOutputStream::writeXMLDecl ()
957 {
958   mStream << "<?xml version=\"1.0\"";
959 
960   if ( !mEncoding.empty() ) writeAttribute("encoding", mEncoding);
961 
962   mStream << "?>";
963   mStream << endl;
964 }
965 
966 
967 /*
968  * Writes the XML comment:
969  *   <!-- Created by <program name> version <program version>
970  *   on yyyy-MM-dd HH:mm with libsbml version <libsbml version>. -->
971  */
972 void
writeComment(const std::string & programName,const std::string & programVersion,bool writeTimestamp)973 XMLOutputStream::writeComment (const std::string& programName,
974                                const std::string& programVersion,
975                                bool writeTimestamp)
976 {
977   // don't write without program name
978   if (programName.empty())
979     return;
980 
981   mStream << "<!-- Created by " << programName;
982 
983   // only write program version if we have it
984   if (!programVersion.empty())
985   {
986     mStream << " version " << programVersion;
987   }
988 
989   // only compute timestamp if we need to
990   if (writeTimestamp)
991   {
992     char formattedDateAndTime[17];
993     time_t tim=time(NULL);
994     tm *now=localtime(&tim);
995 
996 #if ( __cplusplus > 201103L  )
997     snprintf(formattedDateAndTime, 17, "%d-%02d-%02d %02d:%02d",
998             now->tm_year+1900, now->tm_mon+1, now->tm_mday,
999             now->tm_hour, now->tm_min);
1000 #else
1001     sprintf(formattedDateAndTime, "%d-%02d-%02d %02d:%02d",
1002             now->tm_year+1900, now->tm_mon+1, now->tm_mday,
1003             now->tm_hour, now->tm_min);
1004 #endif
1005     mStream << " on " << formattedDateAndTime;
1006   }
1007 
1008   // write library information
1009   if (!mLibraryName.empty())
1010   {
1011     mStream << " with " << mLibraryName;
1012 
1013     if (!mLibraryVersion.empty())
1014     {
1015       mStream << " version " << mLibraryVersion;
1016     }
1017   }
1018 
1019   mStream << ". -->";
1020   mStream << endl;
1021 
1022 }
1023 
1024 
1025 /*
1026  * Outputs the given characters to the underlying stream.
1027  */
1028 XMLOutputStream&
operator <<(const std::string & chars)1029 XMLOutputStream::operator<< (const std::string& chars)
1030 {
1031   if (mInStart)
1032   {
1033     mInStart = false;
1034     mStream << '>';
1035   }
1036 
1037   writeChars(chars);
1038   mInText = true;
1039   mSkipNextIndent = true;
1040 
1041   return *this;
1042 }
1043 
1044 
1045 /*
1046  * Outputs the given double to the underlying stream.
1047  */
1048 XMLOutputStream&
operator <<(const double & value)1049 XMLOutputStream::operator<< (const double& value)
1050 {
1051   if (mInStart)
1052   {
1053     mInStart = false;
1054     mStream << '>';
1055   }
1056 
1057   mStream << value;
1058 
1059   return *this;
1060 }
1061 
1062 
1063 /*
1064  * Outputs the given long to the underlying stream.
1065  */
1066 XMLOutputStream&
operator <<(const long & value)1067 XMLOutputStream::operator<< (const long& value)
1068 {
1069   if (mInStart)
1070   {
1071     mInStart = false;
1072     mStream << '>';
1073   }
1074 
1075   mStream << value;
1076 
1077   return *this;
1078 }
1079 
1080 
1081 /**
1082  * Outputs a single character to the underlying stream.
1083  */
1084 XMLOutputStream&
operator <<(const char & c)1085 XMLOutputStream::operator<< (const char& c)
1086 {
1087   if (c == '&' && mNextAmpersandIsRef)
1088   {
1089     // outputs '&' as-is because the '&' is the first letter
1090     // of a character reference (e.g. &#0168; )
1091     mStream << c;
1092     mNextAmpersandIsRef = false;
1093     return *this;
1094   }
1095 
1096   switch (c)
1097   {
1098     case '&' : mStream << "&amp;" ; break;
1099     case '\'': mStream << "&apos;"; break;
1100     case '<' : mStream << "&lt;"  ; break;
1101     case '>' : mStream << "&gt;"  ; break;
1102     case '"' : mStream << "&quot;"; break;
1103     default  : mStream << c;        break;
1104   }
1105 
1106   return *this;
1107 }
1108 
1109 
1110 SBMLNamespaces *
getSBMLNamespaces()1111 XMLOutputStream::getSBMLNamespaces()
1112 {
1113   return mSBMLns;
1114 }
1115 
1116 void
setSBMLNamespaces(SBMLNamespaces * sbmlns)1117 XMLOutputStream::setSBMLNamespaces(SBMLNamespaces * sbmlns)
1118 {
1119   if (mSBMLns  != NULL)
1120     delete mSBMLns;
1121 
1122   if (sbmlns != NULL)
1123     mSBMLns = sbmlns->clone();
1124   else
1125     mSBMLns = NULL;
1126 }
1127 
getWriteComment()1128 bool XMLOutputStream::getWriteComment()
1129 {
1130   return mWriteComment;
1131 }
1132 
setWriteComment(bool writeComment)1133 void XMLOutputStream::setWriteComment(bool writeComment)
1134 {
1135   mWriteComment = writeComment;
1136 }
1137 
getWriteTimestamp()1138 bool XMLOutputStream::getWriteTimestamp()
1139 {
1140   return mWriteTimestamp;
1141 }
1142 
setWriteTimestamp(bool writeTimestamp)1143 void XMLOutputStream::setWriteTimestamp(bool writeTimestamp)
1144 {
1145   mWriteTimestamp = writeTimestamp;
1146 }
1147 
getLibraryName()1148 string XMLOutputStream::getLibraryName()
1149 {
1150   return mLibraryName;
1151 }
1152 
setLibraryName(const string & libraryName)1153 void XMLOutputStream::setLibraryName(const string& libraryName)
1154 {
1155   mLibraryName = libraryName;
1156 }
1157 
getLibraryVersion()1158 string XMLOutputStream::getLibraryVersion()
1159 {
1160   return mLibraryVersion;
1161 }
1162 
setLibraryVersion(const string & libraryVersion)1163 void XMLOutputStream::setLibraryVersion(const string& libraryVersion)
1164 {
1165   mLibraryVersion = libraryVersion;
1166 }
1167 
getIndent()1168 unsigned int XMLOutputStream::getIndent()
1169 {
1170   return mIndent;
1171 }
1172 
setIndent(unsigned int indent)1173 void XMLOutputStream::setIndent(unsigned int indent)
1174 {
1175   mIndent = indent;
1176 }
1177 
~XMLOutputStream()1178 XMLOutputStream::~XMLOutputStream()
1179 {
1180   if (mSBMLns != NULL)
1181     delete mSBMLns;
1182 }
1183 
1184 
1185 
XMLOutputStringStream(std::ostringstream & stream,const std::string encoding,bool writeXMLDecl,const std::string programName,const std::string programVersion)1186 XMLOutputStringStream::XMLOutputStringStream (  std::ostringstream& stream
1187                    , const std::string  encoding
1188                    , bool                writeXMLDecl
1189                    , const std::string  programName
1190                    , const std::string  programVersion):
1191   XMLOutputStream(stream, encoding, writeXMLDecl,
1192                     programName, programVersion)
1193     , mString(stream)
1194 
1195 {
1196   setStringStream();
1197 }
1198 
1199 std::ostringstream &
getString()1200 XMLOutputStringStream::getString()
1201 {
1202   return mString;
1203 }
1204 
XMLOwningOutputStringStream(const std::string encoding,bool writeXMLDecl,const std::string programName,const std::string programVersion)1205 XMLOwningOutputStringStream::XMLOwningOutputStringStream (const std::string  encoding
1206                                , bool                writeXMLDecl
1207                                , const std::string  programName
1208                                , const std::string  programVersion)
1209   : XMLOutputStringStream(*(new std::ostringstream), encoding, writeXMLDecl, programName, programVersion)
1210 {
1211 
1212 }
1213 
~XMLOwningOutputStringStream()1214 XMLOwningOutputStringStream::~XMLOwningOutputStringStream()
1215 {
1216   delete &mStream;
1217 }
1218 
1219 
XMLOutputFileStream(std::ofstream & stream,const std::string encoding,bool writeXMLDecl,const std::string programName,const std::string programVersion)1220 XMLOutputFileStream::XMLOutputFileStream (std::ofstream& stream
1221                    , const std::string  encoding
1222                    , bool                writeXMLDecl
1223                    , const std::string  programName
1224                    , const std::string  programVersion)
1225   : XMLOutputStream(stream, encoding, writeXMLDecl,
1226                     programName, programVersion)
1227 {
1228 }
1229 
XMLOwningOutputFileStream(const std::string & filename,const std::string encoding,bool writeXMLDecl,const std::string programName,const std::string programVersion)1230 XMLOwningOutputFileStream::XMLOwningOutputFileStream (
1231                                const std::string&  filename
1232                              , const std::string  encoding
1233                              , bool                writeXMLDecl
1234                              , const std::string  programName
1235                              , const std::string  programVersion)
1236   : XMLOutputFileStream( *(new std::ofstream(filename.c_str(), std::ios::out)),
1237                          encoding, writeXMLDecl, programName, programVersion)
1238 {
1239 }
1240 
~XMLOwningOutputFileStream()1241 XMLOwningOutputFileStream::~XMLOwningOutputFileStream()
1242 {
1243   delete &mStream;
1244 }
1245 
1246 #endif /* __cplusplus */
1247 
1248 
1249 LIBLAX_EXTERN
1250 XMLOutputStream_t *
XMLOutputStream_createAsStdout(const char * encoding,int writeXMLDecl)1251 XMLOutputStream_createAsStdout (const char * encoding, int writeXMLDecl)
1252 {
1253   if (encoding == NULL) return NULL;
1254   return new(nothrow) XMLOutputStream(std::cout, encoding, writeXMLDecl);
1255 }
1256 
1257 
1258 LIBLAX_EXTERN
1259 XMLOutputStream_t *
XMLOutputStream_createAsStdoutWithProgramInfo(const char * encoding,int writeXMLDecl,const char * programName,const char * programVersion)1260 XMLOutputStream_createAsStdoutWithProgramInfo (const char * encoding,
1261         int writeXMLDecl, const char * programName, const char * programVersion)
1262 {
1263   if (encoding == NULL) return NULL;
1264   return new(nothrow) XMLOutputStream(std::cout, encoding, writeXMLDecl,
1265                                  programName, programVersion);
1266 }
1267 
1268 
1269 LIBLAX_EXTERN
1270 XMLOutputStream_t *
XMLOutputStream_createAsString(const char * encoding,int writeXMLDecl)1271 XMLOutputStream_createAsString (const char * encoding, int writeXMLDecl)
1272 {
1273   if (encoding == NULL) return NULL;
1274 
1275   return new(nothrow) XMLOwningOutputStringStream(encoding, writeXMLDecl);
1276 }
1277 
1278 
1279 LIBLAX_EXTERN
1280 XMLOutputStream_t *
XMLOutputStream_createAsStringWithProgramInfo(const char * encoding,int writeXMLDecl,const char * programName,const char * programVersion)1281 XMLOutputStream_createAsStringWithProgramInfo (const char * encoding,
1282         int writeXMLDecl, const char * programName, const char * programVersion)
1283 {
1284   if (encoding == NULL) return NULL;
1285 
1286   return new(nothrow) XMLOwningOutputStringStream(encoding, writeXMLDecl,
1287                              programName, programVersion);
1288 }
1289 
1290 
1291 LIBLAX_EXTERN
1292 XMLOutputStream_t *
XMLOutputStream_createFile(const char * filename,const char * encoding,int writeXMLDecl)1293 XMLOutputStream_createFile (const char * filename, const char * encoding,
1294                             int writeXMLDecl)
1295 {
1296   if (filename == NULL || encoding == NULL) return NULL;
1297 
1298   XMLOutputStream_t * out = new(nothrow)
1299                            XMLOwningOutputFileStream(filename, encoding, writeXMLDecl);
1300 
1301   return out;
1302 }
1303 
1304 
1305 LIBLAX_EXTERN
1306 XMLOutputStream_t *
XMLOutputStream_createFileWithProgramInfo(const char * filename,const char * encoding,int writeXMLDecl,const char * programName,const char * programVersion)1307 XMLOutputStream_createFileWithProgramInfo (const char * filename,
1308                                            const char * encoding,
1309         int writeXMLDecl, const char * programName, const char * programVersion)
1310 {
1311   if (filename == NULL || encoding == NULL) return NULL;
1312 
1313   XMLOutputStream_t * out = new(nothrow)
1314                            XMLOwningOutputFileStream(filename, encoding, writeXMLDecl,
1315                            programName, programVersion);
1316 
1317   return out;
1318 }
1319 
1320 
1321 LIBLAX_EXTERN
1322 void
XMLOutputStream_free(XMLOutputStream_t * stream)1323 XMLOutputStream_free (XMLOutputStream_t *stream)
1324 {
1325   if (stream == NULL) return;
1326   delete static_cast<XMLOutputStream*>(stream);
1327 }
1328 
1329 
1330 LIBLAX_EXTERN
1331 void
XMLOutputStream_writeXMLDecl(XMLOutputStream_t * stream)1332 XMLOutputStream_writeXMLDecl (XMLOutputStream_t *stream)
1333 {
1334   if (stream == NULL) return;
1335   stream->writeXMLDecl();
1336 }
1337 
1338 
1339 LIBLAX_EXTERN
1340 void
XMLOutputStream_upIndent(XMLOutputStream_t * stream)1341 XMLOutputStream_upIndent(XMLOutputStream_t *stream)
1342 {
1343   if (stream == NULL) return;
1344   stream->upIndent();
1345 }
1346 
1347 
1348 LIBLAX_EXTERN
1349 void
XMLOutputStream_downIndent(XMLOutputStream_t * stream)1350 XMLOutputStream_downIndent(XMLOutputStream_t *stream)
1351 {
1352   if (stream == NULL) return;
1353   stream->downIndent();
1354 }
1355 
1356 
1357 LIBLAX_EXTERN
1358 void
XMLOutputStream_endElement(XMLOutputStream_t * stream,const char * name)1359 XMLOutputStream_endElement (XMLOutputStream_t *stream, const char* name)
1360 {
1361   if(stream == NULL) return;
1362   stream->endElement(name);
1363 }
1364 
1365 
1366 LIBLAX_EXTERN
1367 void
XMLOutputStream_endElementTriple(XMLOutputStream_t * stream,const XMLTriple_t * triple)1368 XMLOutputStream_endElementTriple (XMLOutputStream_t *stream,
1369                                   const XMLTriple_t *triple)
1370 {
1371   if (stream == NULL || triple == NULL) return;
1372   stream->endElement(*triple);
1373 }
1374 
1375 
1376 LIBLAX_EXTERN
1377 void
XMLOutputStream_setAutoIndent(XMLOutputStream_t * stream,int indent)1378 XMLOutputStream_setAutoIndent (XMLOutputStream_t *stream, int indent)
1379 {
1380   if (stream == NULL) return;
1381   stream->setAutoIndent(static_cast<bool>(indent));
1382 }
1383 
1384 
1385 LIBLAX_EXTERN
1386 void
XMLOutputStream_startElement(XMLOutputStream_t * stream,const char * name)1387 XMLOutputStream_startElement (XMLOutputStream_t *stream, const char* name)
1388 {
1389   if (stream == NULL) return;
1390   stream->startElement(name);
1391 }
1392 
1393 
1394 LIBLAX_EXTERN
1395 void
XMLOutputStream_startElementTriple(XMLOutputStream_t * stream,const XMLTriple_t * triple)1396 XMLOutputStream_startElementTriple (XMLOutputStream_t *stream,
1397                                     const XMLTriple_t *triple)
1398 {
1399   if (stream == NULL || triple == NULL) return;
1400   stream->startElement(*triple);
1401 }
1402 
1403 
1404 LIBLAX_EXTERN
1405 void
XMLOutputStream_startEndElement(XMLOutputStream_t * stream,const char * name)1406 XMLOutputStream_startEndElement (XMLOutputStream_t *stream, const char* name)
1407 {
1408   if (stream == NULL) return;
1409   stream->startEndElement(name);
1410 }
1411 
1412 
1413 LIBLAX_EXTERN
1414 void
XMLOutputStream_startEndElementTriple(XMLOutputStream_t * stream,const XMLTriple_t * triple)1415 XMLOutputStream_startEndElementTriple (XMLOutputStream_t *stream,
1416                                        const XMLTriple_t *triple)
1417 {
1418   if (stream == NULL || triple == NULL) return;
1419   stream->startEndElement(*triple);
1420 }
1421 
1422 
1423 LIBLAX_EXTERN
1424 void
XMLOutputStream_writeAttributeChars(XMLOutputStream_t * stream,const char * name,const char * chars)1425 XMLOutputStream_writeAttributeChars (XMLOutputStream_t *stream,
1426                                      const char* name, const char* chars)
1427 {
1428   if (stream == NULL) return;
1429   stream->writeAttribute(name, string(chars));
1430 }
1431 
1432 
1433 LIBLAX_EXTERN
1434 void
XMLOutputStream_writeAttributeCharsTriple(XMLOutputStream_t * stream,const XMLTriple_t * triple,const char * chars)1435 XMLOutputStream_writeAttributeCharsTriple (XMLOutputStream_t *stream,
1436                                            const XMLTriple_t *triple,
1437                                            const char* chars)
1438 {
1439   if (stream == NULL || triple == NULL) return;
1440   stream->writeAttribute(*triple, string(chars));
1441 }
1442 
1443 
1444 LIBLAX_EXTERN
1445 void
XMLOutputStream_writeAttributeBool(XMLOutputStream_t * stream,const char * name,const int flag)1446 XMLOutputStream_writeAttributeBool (XMLOutputStream_t *stream,
1447                                     const char* name,
1448                                     const int flag)
1449 {
1450   if (stream == NULL) return;
1451   stream->writeAttribute(name, static_cast<bool>(flag));
1452 }
1453 
1454 
1455 LIBLAX_EXTERN
1456 void
XMLOutputStream_writeAttributeBoolTriple(XMLOutputStream_t * stream,const XMLTriple_t * triple,const int flag)1457 XMLOutputStream_writeAttributeBoolTriple (XMLOutputStream_t *stream,
1458                                           const XMLTriple_t *triple,
1459                                           const int flag)
1460 {
1461   if (stream == NULL || triple == NULL) return;
1462   stream->writeAttribute(*triple, static_cast<bool>(flag));
1463 }
1464 
1465 
1466 LIBLAX_EXTERN
1467 void
XMLOutputStream_writeAttributeDouble(XMLOutputStream_t * stream,const char * name,const double value)1468 XMLOutputStream_writeAttributeDouble (XMLOutputStream_t *stream,
1469                                       const char* name,
1470                                       const double value)
1471 {
1472   if (stream == NULL) return;
1473   stream->writeAttribute(name, value);
1474 }
1475 
1476 
1477 LIBLAX_EXTERN
1478 void
XMLOutputStream_writeAttributeDoubleTriple(XMLOutputStream_t * stream,const XMLTriple_t * triple,const double value)1479 XMLOutputStream_writeAttributeDoubleTriple (XMLOutputStream_t *stream,
1480                                             const XMLTriple_t *triple,
1481                                             const double value)
1482 {
1483   if (stream == NULL || triple == NULL) return;
1484   stream->writeAttribute(*triple, value);
1485 }
1486 
1487 
1488 LIBLAX_EXTERN
1489 void
XMLOutputStream_writeAttributeLong(XMLOutputStream_t * stream,const char * name,const long value)1490 XMLOutputStream_writeAttributeLong (XMLOutputStream_t *stream,
1491                                     const char* name,
1492                                     const long value)
1493 {
1494   if (stream == NULL) return;
1495   stream->writeAttribute(name, value);
1496 }
1497 
1498 
1499 LIBLAX_EXTERN
1500 void
XMLOutputStream_writeAttributeLongTriple(XMLOutputStream_t * stream,const XMLTriple_t * triple,const long value)1501 XMLOutputStream_writeAttributeLongTriple (XMLOutputStream_t *stream,
1502                                           const XMLTriple_t *triple,
1503                                           const long value)
1504 {
1505   if (stream == NULL || triple == NULL) return;
1506   stream->writeAttribute(*triple, value);
1507 }
1508 
1509 
1510 LIBLAX_EXTERN
1511 void
XMLOutputStream_writeAttributeInt(XMLOutputStream_t * stream,const char * name,const int value)1512 XMLOutputStream_writeAttributeInt (XMLOutputStream_t *stream,
1513                                    const char* name,
1514                                    const int value)
1515 {
1516   if (stream == NULL) return;
1517   stream->writeAttribute(name, value);
1518 }
1519 
1520 
1521 LIBLAX_EXTERN
1522 void
XMLOutputStream_writeAttributeIntTriple(XMLOutputStream_t * stream,const XMLTriple_t * triple,const int value)1523 XMLOutputStream_writeAttributeIntTriple (XMLOutputStream_t *stream,
1524                                          const XMLTriple_t *triple,
1525                                          const int value)
1526 {
1527   if (stream == NULL || triple == NULL) return;
1528   stream->writeAttribute(*triple, value);
1529 }
1530 
1531 
1532 LIBLAX_EXTERN
1533 void
XMLOutputStream_writeAttributeUInt(XMLOutputStream_t * stream,const char * name,const unsigned int value)1534 XMLOutputStream_writeAttributeUInt (XMLOutputStream_t *stream,
1535                                     const char* name,
1536                                     const unsigned int value)
1537 {
1538   if (stream == NULL) return;
1539   stream->writeAttribute(name, value);
1540 }
1541 
1542 
1543 LIBLAX_EXTERN
1544 void
XMLOutputStream_writeAttributeUIntTriple(XMLOutputStream_t * stream,const XMLTriple_t * triple,const unsigned int value)1545 XMLOutputStream_writeAttributeUIntTriple (XMLOutputStream_t *stream,
1546                                           const XMLTriple_t *triple,
1547                                           const unsigned int value)
1548 {
1549   if (stream == NULL) return;
1550   stream->writeAttribute(*triple, value);
1551 }
1552 
1553 
1554 LIBLAX_EXTERN
1555 void
XMLOutputStream_writeChars(XMLOutputStream_t * stream,const char * chars)1556 XMLOutputStream_writeChars (XMLOutputStream_t *stream, const char* chars)
1557 {
1558   if (stream == NULL || chars == NULL) return;
1559   stream->operator <<(chars);
1560 }
1561 
1562 
1563 LIBLAX_EXTERN
1564 void
XMLOutputStream_writeDouble(XMLOutputStream_t * stream,const double value)1565 XMLOutputStream_writeDouble (XMLOutputStream_t *stream, const double value)
1566 {
1567   if (stream == NULL) return;
1568   stream->operator <<(value);
1569 }
1570 
1571 
1572 LIBLAX_EXTERN
1573 void
XMLOutputStream_writeLong(XMLOutputStream_t * stream,const long value)1574 XMLOutputStream_writeLong (XMLOutputStream_t *stream, const long value)
1575 {
1576   if (stream == NULL) return;
1577   stream->operator <<(value);
1578 }
1579 
1580 
1581 LIBLAX_EXTERN
1582 const char *
XMLOutputStream_getString(XMLOutputStream_t * stream)1583 XMLOutputStream_getString(XMLOutputStream_t* stream)
1584 {
1585   if (stream == NULL) return NULL;
1586 
1587   if (stream->getStringStream())
1588   {
1589     std::string buffer = static_cast <XMLOutputStringStream*>
1590                                                   (stream)->getString().str();
1591     return safe_strdup(buffer.c_str());
1592   }
1593   else
1594     return "";
1595 }
1596 
1597 
1598 LIBSBML_CPP_NAMESPACE_END
1599 /** @endcond */
1600