summaryrefslogtreecommitdiff
path: root/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGOutput.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Build/source/texk/dvisvgm/dvisvgm-src/src/SVGOutput.cpp')
-rw-r--r--Build/source/texk/dvisvgm/dvisvgm-src/src/SVGOutput.cpp174
1 files changed, 174 insertions, 0 deletions
diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGOutput.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGOutput.cpp
new file mode 100644
index 00000000000..26621d49303
--- /dev/null
+++ b/Build/source/texk/dvisvgm/dvisvgm-src/src/SVGOutput.cpp
@@ -0,0 +1,174 @@
+/*************************************************************************
+** SVGOutput.cpp **
+** **
+** This file is part of dvisvgm -- the DVI to SVG converter **
+** Copyright (C) 2005-2015 Martin Gieseking <martin.gieseking@uos.de> **
+** **
+** This program is free software; you can redistribute it and/or **
+** modify it under the terms of the GNU General Public License as **
+** published by the Free Software Foundation; either version 3 of **
+** the License, or (at your option) any later version. **
+** **
+** This program is distributed in the hope that it will be useful, but **
+** WITHOUT ANY WARRANTY; without even the implied warranty of **
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the **
+** GNU General Public License for more details. **
+** **
+** You should have received a copy of the GNU General Public License **
+** along with this program; if not, see <http://www.gnu.org/licenses/>. **
+*************************************************************************/
+
+#include <algorithm>
+#include <cmath>
+#include <iomanip>
+#include <iostream>
+#include <sstream>
+#include "gzstream.h"
+#include "Calculator.h"
+#include "FileSystem.h"
+#include "Message.h"
+#include "SVGOutput.h"
+
+
+using namespace std;
+
+SVGOutput::SVGOutput (const char *base, string pattern, int zipLevel)
+ : _path(base ? base : ""),
+ _pattern(pattern),
+ _stdout(base == 0),
+ _zipLevel(zipLevel),
+ _page(-1),
+ _os(0)
+{
+}
+
+
+/** Returns an output stream for the given page.
+ * @param[in] page number of current page
+ * @param[in] numPages total number of pages in the DVI file
+ * @return output stream for the given page */
+ostream& SVGOutput::getPageStream (int page, int numPages) const {
+ string fname = filename(page, numPages);
+ if (fname.empty()) {
+ delete _os;
+ _os = 0;
+ return cout;
+ }
+ if (page == _page)
+ return *_os;
+
+ _page = page;
+ delete _os;
+ if (_zipLevel > 0)
+ _os = new ogzstream(fname.c_str(), _zipLevel);
+ else
+ _os = new ofstream(fname.c_str());
+ if (!_os || !*_os) {
+ delete _os;
+ _os = 0;
+ throw MessageException("can't open file "+fname+" for writing");
+ }
+ return *_os;
+}
+
+
+/** Returns the name of the SVG file containing the given page.
+ * @param[in] page number of current page
+ * @param[in] numPages total number of pages */
+string SVGOutput::filename (int page, int numPages) const {
+ if (_stdout)
+ return "";
+ string pattern = _pattern;
+ expandFormatString(pattern, page, numPages);
+ // remove leading and trailing whitespace
+ stringstream trim;
+ trim << pattern;
+ pattern.clear();
+ trim >> pattern;
+ // set and expand default pattern if necessary
+ if (pattern.empty()) {
+ pattern = numPages > 1 ? "%f-%p" : "%f";
+ expandFormatString(pattern, page, numPages);
+ }
+ // append suffix if necessary
+ FilePath outpath(pattern, true);
+ if (outpath.suffix().empty())
+ outpath.suffix(_zipLevel > 0 ? "svgz" : "svg");
+ string abspath = outpath.absolute();
+ string relpath = outpath.relative();
+ return abspath.length() < relpath.length() ? abspath : relpath;
+}
+
+
+static int ilog10 (int n) {
+ int result = 0;
+ while (n >= 10) {
+ result++;
+ n /= 10;
+ }
+ return result;
+}
+
+
+/** Replace expressions in a given string by the corresponing values.
+ * Supported constructs:
+ * %f: basename of the current file (filename without suffix)
+ * %[0-9]?p: current page number
+ * %[0-9]?P: number of pages in DVI file
+ * %[0-9]?(expr): arithmetic expression */
+void SVGOutput::expandFormatString (string &str, int page, int numPages) const {
+ string result;
+ while (!str.empty()) {
+ size_t pos = str.find('%');
+ if (pos == string::npos) {
+ result += str;
+ str.clear();
+ }
+ else {
+ result += str.substr(0, pos);
+ str = str.substr(pos);
+ pos = 1;
+ ostringstream oss;
+ if (isdigit(str[pos])) {
+ oss << setw(str[pos]-'0') << setfill('0');
+ pos++;
+ }
+ else {
+ oss << setw(ilog10(numPages)+1) << setfill('0');
+ }
+ switch (str[pos]) {
+ case 'f':
+ result += _path.basename();
+ break;
+ case 'p':
+ case 'P':
+ oss << (str[pos] == 'p' ? page : numPages);
+ result += oss.str();
+ break;
+ case '(': {
+ size_t endpos = str.find(')', pos);
+ if (endpos == string::npos)
+ throw MessageException("missing ')' in filename pattern");
+ else if (endpos-pos-1 > 1) {
+ try {
+ Calculator calculator;
+ calculator.setVariable("p", page);
+ calculator.setVariable("P", numPages);
+ oss << floor(calculator.eval(str.substr(pos, endpos-pos+1)));
+ result += oss.str();
+ }
+ catch (CalculatorException &e) {
+ oss.str("");
+ oss << "error in filename pattern (" << e.what() << ")";
+ throw MessageException(oss.str());
+ }
+ pos = endpos;
+ }
+ break;
+ }
+ }
+ str = str.substr(pos+1);
+ }
+ }
+ str = result;
+}