1 /**
2 * @file SedWriter.cpp
3 * @brief Implementation of the SedWriter class.
4 * @author DEVISER
5 *
6 * <!--------------------------------------------------------------------------
7 * This file is part of libSEDML. Please visit http://sed-ml.org for more
8 * information about SED-ML. The latest version of libSEDML can be found on
9 * github: https://github.com/fbergmann/libSEDML/
10 *
11
12 * Copyright (c) 2013-2019, Frank T. Bergmann
13 * All rights reserved.
14 *
15
16 * Redistribution and use in source and binary forms, with or without
17 * modification, are permitted provided that the following conditions are met:
18 *
19
20 * 1. Redistributions of source code must retain the above copyright notice,
21 * this
22 * list of conditions and the following disclaimer.
23 * 2. Redistributions in binary form must reproduce the above copyright notice,
24 * this list of conditions and the following disclaimer in the documentation
25 * and/or other materials provided with the distribution.
26 *
27 * This library is free software; you can redistribute it and/or modify it
28 * under the terms of the GNU Lesser General Public License as published by the
29 * Free Software Foundation. A copy of the license agreement is provided in the
30 * file named "LICENSE.txt" included with this software distribution and also
31 * available online as http://sbml.org/software/libsbml/license.html
32 * ------------------------------------------------------------------------ -->
33 */
34
35
36 #include <ios>
37 #include <iostream>
38 #include <fstream>
39 #include <sstream>
40
41 #include <sedml/common/common.h>
42 #include <sbml/xml/XMLOutputStream.h>
43
44 #include <sedml/SedError.h>
45 #include <sedml/SedErrorLog.h>
46 #include <sedml/SedDocument.h>
47 #include <sedml/SedWriter.h>
48
49 #include <sbml/compress/CompressCommon.h>
50 #include <sbml/compress/OutputCompressor.h>
51
52 /** @cond doxygenIgnored */
53
54 using namespace std;
55
56 /** @endcond */
57
58 LIBSEDML_CPP_NAMESPACE_BEGIN
59
60 #ifdef __cplusplus
61
62 /*
63 * Creates a new SedWriter.
64 */
SedWriter()65 SedWriter::SedWriter ()
66 {
67 }
68
69
70 /*
71 * Destroys this SedWriter.
72 */
~SedWriter()73 SedWriter::~SedWriter ()
74 {
75 }
76
77
78 /*
79 * Sets the name of this program. i.\ e.\ the one about to write out the
80 * SedDocument. If the program name and version are set
81 * (setProgramVersion()), the following XML comment, intended for human
82 * consumption, will be written at the beginning of the document:
83 *
84 * <!-- Created by <program name> version <program version>
85 * on yyyy-MM-dd HH:mm with libsedml version <libsedml version>. -->
86 */
87 int
setProgramName(const std::string & name)88 SedWriter::setProgramName (const std::string& name)
89 {
90 mProgramName = name;
91 return LIBSEDML_OPERATION_SUCCESS;
92 }
93
94
95 /*
96 * Sets the version of this program. i.\ e.\ the one about to write out the
97 * SedDocument. If the program version and name are set
98 * (setProgramName()), the following XML comment, intended for human
99 * consumption, will be written at the beginning of the document:
100 *
101 * <!-- Created by <program name> version <program version>
102 * on yyyy-MM-dd HH:mm with libsedml version <libsedml version>. -->
103 */
104 int
setProgramVersion(const std::string & version)105 SedWriter::setProgramVersion (const std::string& version)
106 {
107 mProgramVersion = version;
108 return LIBSEDML_OPERATION_SUCCESS;
109 }
110
111
112 /*
113 * Writes the given SedDocument to filename.
114 *
115 * If the filename ends with @em .gz, the file will be compressed by @em gzip.
116 * Similary, if the filename ends with @em .zip or @em .bz2, the file will be
117 * compressed by @em zip or @em bzip2, respectively. Otherwise, the fill will be
118 * uncompressed.
119 *
120 * @note To create a gzip/zip file, underlying libSEDML needs to be linked with zlib at
121 * compile time. Also, underlying libSEDML needs to be linked with bzip2 to create a
122 * bzip2 file.
123 * File unwritable error will be logged and @c false will be returned if a compressed
124 * file name is given and underlying libSEDML is not linked with the corresponding
125 * required library.
126 * SedWriter::hasZlib() and SedWriter::hasBzip2() can be used to check whether
127 * underlying libSEDML is linked with the library.
128 *
129 * @return true on success and false if the filename could not be opened
130 * for writing.
131 */
132 bool
writeSedML(const SedDocument * d,const std::string & filename)133 SedWriter::writeSedML (const SedDocument* d, const std::string& filename)
134 {
135 std::ostream* stream = NULL;
136
137 try
138 {
139 // open an uncompressed XML file.
140 if ( string::npos != filename.find(".xml", filename.length() - 4) )
141 {
142 stream = new(std::nothrow) std::ofstream(filename.c_str());
143 }
144 // open a gzip file
145 else if ( string::npos != filename.find(".gz", filename.length() - 3) )
146 {
147 stream = OutputCompressor::openGzipOStream(filename);
148 }
149 // open a bz2 file
150 else if ( string::npos != filename.find(".bz2", filename.length() - 4) )
151 {
152 stream = OutputCompressor::openBzip2OStream(filename);
153 }
154 // open a zip file
155 else if ( string::npos != filename.find(".zip", filename.length() - 4) )
156 {
157 std::string filenameinzip = filename.substr(0, filename.length() - 4);
158
159 if ( ( string::npos == filenameinzip.find(".xml", filenameinzip.length() - 4) ) &&
160 ( string::npos == filenameinzip.find(".sedml", filenameinzip.length() - 5) )
161 )
162 {
163 filenameinzip += ".xml";
164 }
165
166
167 #if defined(WIN32) && !defined(CYGWIN)
168 char sepr = '\\';
169 #else
170 char sepr = '/';
171 #endif
172 size_t spos = filenameinzip.rfind(sepr, filenameinzip.length() - 1);
173 if( spos != string::npos )
174 {
175 filenameinzip = filenameinzip.substr(spos + 1, filenameinzip.length() - 1);
176 }
177
178
179 stream = OutputCompressor::openZipOStream(filename, filenameinzip);
180 }
181 else
182 {
183 stream = new(std::nothrow) std::ofstream(filename.c_str());
184 }
185 }
186 catch ( ZlibNotLinked& )
187 {
188 // libSEDML is not linked with zlib.
189 XMLErrorLog *log = (const_cast<SedDocument *>(d))->getErrorLog();
190 std::ostringstream oss;
191 oss << "Tried to write " << filename << ". Writing a gzip/zip file is not enabled because "
192 << "underlying libSEDML is not linked with zlib.";
193 log->add(XMLError( XMLFileUnwritable, oss.str(), 0, 0) );
194 return false;
195 }
196 catch ( Bzip2NotLinked& )
197 {
198 // libSEDML is not linked with bzip2.
199 XMLErrorLog *log = (const_cast<SedDocument *>(d))->getErrorLog();
200 std::ostringstream oss;
201 oss << "Tried to write " << filename << ". Writing a bzip2 file is not enabled because "
202 << "underlying libSEDML is not linked with bzip2.";
203 log->add(XMLError( XMLFileUnwritable, oss.str(), 0, 0) );
204 return false;
205 }
206
207
208 if ( stream == NULL || stream->fail() || stream->bad())
209 {
210 SedErrorLog *log = (const_cast<SedDocument *>(d))->getErrorLog();
211 log->logError(XMLFileUnwritable);
212 delete stream;
213 return false;
214 }
215
216 bool result = writeSedML(d, *stream);
217 delete stream;
218
219 return result;
220
221 }
222
223
224 /*
225 * Writes the given SedDocument to the output stream.
226 *
227 * @return true on success and false if one of the underlying parser
228 * components fail (rare).
229 */
230 bool
writeSedML(const SedDocument * d,std::ostream & stream)231 SedWriter::writeSedML (const SedDocument* d, std::ostream& stream)
232 {
233 bool result = false;
234
235 try
236 {
237 stream.exceptions(ios_base::badbit | ios_base::failbit | ios_base::eofbit);
238 XMLOutputStream xos(stream, "UTF-8", true, mProgramName,
239 mProgramVersion);
240 d->write(xos);
241 stream << endl;
242
243 result = true;
244 }
245 catch (ios_base::failure&)
246 {
247 SedErrorLog *log = (const_cast<SedDocument *>(d))->getErrorLog();
248 log->logError(XMLFileOperationError);
249 }
250
251 return result;
252 }
253
254
255 /** @cond doxygenLibsedmlInternal */
256 /*
257 * Writes the given SedDocument to an in-memory string and returns a
258 * pointer to it. The string is owned by the caller and should be freed
259 * (with free()) when no longer needed.
260 *
261 * @return the string on success and 0 if one of the underlying parser
262 * components fail (rare).
263 */
264 LIBSEDML_EXTERN
265 char*
writeToString(const SedDocument * d)266 SedWriter::writeToString (const SedDocument* d)
267 {
268 ostringstream stream;
269 writeSedML(d, stream);
270
271 return safe_strdup( stream.str().c_str() );
272 }
273
274 std::string
writeSedMLToStdString(const SedDocument * d)275 SedWriter::writeSedMLToStdString(const SedDocument* d)
276 {
277 if (d == NULL) return "";
278
279 ostringstream stream;
280 writeSedML(d, stream);
281 return stream.str();
282 }
283
284 LIBSEDML_EXTERN
285 char*
writeSedMLToString(const SedDocument * d)286 SedWriter::writeSedMLToString (const SedDocument* d)
287 {
288 return writeToString(d);
289 }
290 /** @endcond */
291
292
293 LIBSEDML_EXTERN
294 bool
writeSedMLToFile(const SedDocument * d,const std::string & filename)295 SedWriter::writeSedMLToFile (const SedDocument* d, const std::string& filename)
296 {
297 return writeSedML(d, filename);
298 }
299
300
301 /*
302 * Predicate returning @c true if
303 * underlying libSEDML is linked with zlib.
304 *
305 * @return @c true if libSEDML is linked with zlib, @c false otherwise.
306 */
307 bool
hasZlib()308 SedWriter::hasZlib()
309 {
310 return LIBSBML_CPP_NAMESPACE ::hasZlib();
311 }
312
313
314 /*
315 * Predicate returning @c true if
316 * underlying libSEDML is linked with bzip2.
317 *
318 * @return @c true if libSEDML is linked with bzip2, @c false otherwise.
319 */
320 bool
hasBzip2()321 SedWriter::hasBzip2()
322 {
323 return LIBSBML_CPP_NAMESPACE ::hasBzip2();
324 }
325
326
327 #endif /* __cplusplus */
328 /** @cond doxygenIgnored */
329 LIBSEDML_EXTERN
330 SedWriter_t *
SedWriter_create()331 SedWriter_create ()
332 {
333 return new(nothrow) SedWriter;
334 }
335
336
337 LIBSEDML_EXTERN
338 void
SedWriter_free(SedWriter_t * sw)339 SedWriter_free (SedWriter_t *sw)
340 {
341 delete sw;
342 }
343
344
345 LIBSEDML_EXTERN
346 int
SedWriter_setProgramName(SedWriter_t * sw,const char * name)347 SedWriter_setProgramName (SedWriter_t *sw, const char *name)
348 {
349 if (sw != NULL)
350 return (name == NULL) ? sw->setProgramName("") : sw->setProgramName(name);
351 else
352 return LIBSEDML_INVALID_OBJECT;
353 }
354
355
356 LIBSEDML_EXTERN
357 int
SedWriter_setProgramVersion(SedWriter_t * sw,const char * version)358 SedWriter_setProgramVersion (SedWriter_t *sw, const char *version)
359 {
360 if (sw != NULL)
361 return (version == NULL) ? sw->setProgramVersion("") :
362 sw->setProgramVersion(version);
363 else
364 return LIBSEDML_INVALID_OBJECT;
365 }
366
367
368 LIBSEDML_EXTERN
369 int
SedWriter_writeSedML(SedWriter_t * sw,const SedDocument_t * d,const char * filename)370 SedWriter_writeSedML ( SedWriter_t *sw,
371 const SedDocument_t *d,
372 const char *filename )
373 {
374 if (sw == NULL || d == NULL)
375 return 0;
376 else
377 return (filename != NULL) ?
378 static_cast<int>( sw->writeSedML(d, filename) ) : 0;
379 }
380
381
382 LIBSEDML_EXTERN
383 int
SedWriter_writeSedMLToFile(SedWriter_t * sw,const SedDocument_t * d,const char * filename)384 SedWriter_writeSedMLToFile ( SedWriter_t *sw,
385 const SedDocument_t *d,
386 const char *filename )
387 {
388 if (sw == NULL || d == NULL)
389 return 0;
390 else
391 return (filename != NULL) ?
392 static_cast<int>( sw->writeSedML(d, filename) ) : 0;
393 }
394
395
396 LIBSEDML_EXTERN
397 char *
SedWriter_writeSedMLToString(SedWriter_t * sw,const SedDocument_t * d)398 SedWriter_writeSedMLToString (SedWriter_t *sw, const SedDocument_t *d)
399 {
400 if (sw == NULL || d == NULL)
401 return 0;
402 else
403 return sw->writeToString(d);
404 }
405
406
407 LIBSEDML_EXTERN
408 int
SedWriter_hasZlib()409 SedWriter_hasZlib ()
410 {
411 return static_cast<int>( SedWriter::hasZlib() );
412 }
413
414
415 LIBSEDML_EXTERN
416 int
SedWriter_hasBzip2()417 SedWriter_hasBzip2 ()
418 {
419 return static_cast<int>( SedWriter::hasBzip2() );
420 }
421
422
423 LIBSEDML_EXTERN
424 int
writeSedML(const SedDocument_t * d,const char * filename)425 writeSedML (const SedDocument_t *d, const char *filename)
426 {
427 SedWriter sw;
428 if (d == NULL || filename == NULL)
429 return 0;
430 else
431 return static_cast<int>( sw.writeSedML(d, filename) );
432 }
433
434
435 LIBSEDML_EXTERN
436 int
writeSedMLToFile(const SedDocument_t * d,const char * filename)437 writeSedMLToFile (const SedDocument_t *d, const char *filename)
438 {
439 SedWriter sw;
440 if (d == NULL || filename == NULL)
441 return 0;
442 else
443 return static_cast<int>( sw.writeSedML(d, filename) );
444 }
445
446
447 LIBSEDML_EXTERN
448 char *
writeSedMLToString(const SedDocument_t * d)449 writeSedMLToString (const SedDocument_t *d)
450 {
451 SedWriter sw;
452 if (d == NULL)
453 return NULL;
454 else
455 return sw.writeToString(d);
456 }
457
458 LIBSEDML_EXTERN
writeSedMLToStdString(const SedDocument * d)459 std::string writeSedMLToStdString(const SedDocument* d)
460 {
461 SedWriter sw;
462 if (d == NULL)
463 return "";
464 else
465 return sw.writeSedMLToStdString(d);
466 }
467 /** @endcond */
468
469 LIBSEDML_CPP_NAMESPACE_END
470
471