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. ¨ ) 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. ¹ ) 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) &
149 * 2) '
150 * 3) <
151 * 4) >
152 * 5) "
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("&",index) == index)
164 {
165 return true;
166 }
167 else if (chars.find("'",index) == index)
168 {
169 return true;
170 }
171 else if (chars.find("<",index) == index)
172 {
173 return true;
174 }
175 else if (chars.find(">",index) == index)
176 {
177 return true;
178 }
179 else if (chars.find(""",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. ¨ )
1091 mStream << c;
1092 mNextAmpersandIsRef = false;
1093 return *this;
1094 }
1095
1096 switch (c)
1097 {
1098 case '&' : mStream << "&" ; break;
1099 case '\'': mStream << "'"; break;
1100 case '<' : mStream << "<" ; break;
1101 case '>' : mStream << ">" ; break;
1102 case '"' : mStream << """; 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