1 /*
2 blahtex: a TeX to MathML converter designed with MediaWiki in mind
3 blahtexml: an extension of blahtex with XML processing in mind
4 http://gva.noekeon.org/blahtexml
5
6 Copyright (c) 2009, Gilles Van Assche
7 All rights reserved.
8
9 Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
10
11 * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
12 * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
13 * Neither the names of the authors nor the names of their affiliation may be used to endorse or promote products derived from this software without specific prior written permission.
14
15 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
16 */
17
18 #include "AttributesImpl.h"
19 #include "BlahtexFilter.h"
20 #include "mainPng.h"
21 #include "XercesString.h"
22 #include <iostream>
23 #include <xercesc/framework/StdInInputSource.hpp>
24 #include <xercesc/framework/XMLFormatter.hpp>
25 #include <xercesc/parsers/SAX2XMLFilterImpl.hpp>
26 #include <xercesc/sax2/Attributes.hpp>
27 #include <xercesc/sax2/SAX2XMLReader.hpp>
28 #include <xercesc/sax2/XMLReaderFactory.hpp>
29 #include <xercesc/util/OutOfMemoryException.hpp>
30 #include <xercesc/util/PlatformUtils.hpp>
31 #include <xercesc/util/TransService.hpp>
32 #include <xercesc/util/XMLString.hpp>
33 #include <xercesc/util/XMLUniDefs.hpp>
34
35 using namespace std;
36
37 extern wstring GetErrorMessage(const blahtex::Exception& e);
38
BlahtexFilter(SAX2XMLReader * parent,blahtex::Interface & anInterface)39 BlahtexFilter::BlahtexFilter(SAX2XMLReader* parent, blahtex::Interface& anInterface)
40 : SAX2XMLFilterImpl(parent), interface(anInterface), numberOfErrors(0)
41 {
42 }
43
~BlahtexFilter()44 BlahtexFilter::~BlahtexFilter()
45 {
46 }
47
startElement(const XMLCh * const uri,const XMLCh * const localname,const XMLCh * const qname,const Attributes & attributes)48 void BlahtexFilter::startElement(const XMLCh* const uri, const XMLCh* const localname,
49 const XMLCh* const qname, const Attributes& attributes)
50 {
51 static AttributesImpl emptyAttributes;
52 static XercesString empty;
53 static XercesString blahtexmlNamespace("http://gva.noekeon.org/blahtexml");
54 static XercesString m("m");
55 static XercesString inlin("inline");
56 static XercesString block("block");
57 static XercesString error("error");
58 static XercesString display("display");
59
60 bool blockMode = false;
61 bool encloseInMathTag = false;
62 int eqAttrIndex = attributes.getIndex(blahtexmlNamespace.c_str(), m.c_str());
63 if (eqAttrIndex < 0) {
64 eqAttrIndex = attributes.getIndex(blahtexmlNamespace.c_str(), inlin.c_str());
65 encloseInMathTag = (eqAttrIndex >= 0);
66 }
67 if (eqAttrIndex < 0) {
68 eqAttrIndex = attributes.getIndex(blahtexmlNamespace.c_str(), block.c_str());
69 encloseInMathTag = (eqAttrIndex >= 0);
70 blockMode = (eqAttrIndex >= 0);
71 }
72 if (eqAttrIndex >= 0) {
73 try {
74 XercesString inputXerces(attributes.getValue(eqAttrIndex));
75 wstring input = inputXerces.convertTowstring();
76 interface.ProcessInput(input, blockMode);
77
78 AttributesImpl newAttributes(attributes);
79 newAttributes.removeAttribute(eqAttrIndex);
80 SAX2XMLFilterImpl::startElement(uri, localname, qname, newAttributes);
81
82 XercesString MathMLnamespace("http://www.w3.org/1998/Math/MathML");
83 XercesString unprefixedMath(L"math");
84 wstring MathMLprefix;
85 bool MathMLexistingNamespace = getMathMLprefix(MathMLprefix);
86 if ((desiredMathMLPrefixType == PrefixNone) && (!(MathMLprefix == L""))) {
87 MathMLexistingNamespace = false;
88 MathMLprefix = L"";
89 }
90 if ((desiredMathMLPrefixType == PrefixAdd) && (!(MathMLprefix == desiredMathMLPrefix))) {
91 MathMLexistingNamespace = false;
92 MathMLprefix = desiredMathMLPrefix;
93 }
94 XercesString MathMLprefix_(MathMLprefix);
95
96 if (!MathMLexistingNamespace)
97 SAX2XMLFilterImpl::startPrefixMapping(MathMLprefix_.c_str(), MathMLnamespace.c_str());
98 XercesString prefixedMath((MathMLprefix == L"") ? L"math" : (MathMLprefix + L":math"));
99 if (encloseInMathTag) {
100 AttributesImpl mathAttributes;
101 if (blockMode)
102 mathAttributes.addAttribute(display.c_str(), empty.c_str(), display.c_str(), block.c_str(), empty.c_str());
103 SAX2XMLFilterImpl::startElement(MathMLnamespace.c_str(), unprefixedMath.c_str(), prefixedMath.c_str(), mathAttributes);
104 }
105 if (encloseInMathTag && (annotatePNG || annotateTeX)) {
106 static XercesString unprefixedSemantics("semantics");
107 XercesString prefixedSemantics((MathMLprefix == L"") ? L"semantics" : (MathMLprefix + L":semantics"));
108 static XercesString unprefixedMrow("mrow");
109 XercesString prefixedMrow((MathMLprefix == L"") ? L"mrow" : (MathMLprefix + L":mrow"));
110 static XercesString unprefixedAnnotation("annotation");
111 XercesString prefixedAnnotation((MathMLprefix == L"") ? L"annotation" : (MathMLprefix + L":annotation"));
112 static XercesString encoding("encoding");
113 SAX2XMLFilterImpl::startElement(MathMLnamespace.c_str(), unprefixedSemantics.c_str(), prefixedSemantics.c_str(), emptyAttributes);
114 SAX2XMLFilterImpl::startElement(MathMLnamespace.c_str(), unprefixedMrow.c_str(), prefixedMrow.c_str(), emptyAttributes);
115 interface.PrintAsSAX2(*this, MathMLprefix, true);
116 SAX2XMLFilterImpl::endElement(MathMLnamespace.c_str(), unprefixedMrow.c_str(), prefixedMrow.c_str());
117 if (annotateTeX) {
118 static XercesString TeX("TeX");
119 AttributesImpl annotationAttributes;
120 annotationAttributes.addAttribute(encoding.c_str(), empty.c_str(), encoding.c_str(), TeX.c_str(), empty.c_str());
121 SAX2XMLFilterImpl::startElement(MathMLnamespace.c_str(), unprefixedAnnotation.c_str(), prefixedAnnotation.c_str(), annotationAttributes);
122 XercesString purifiedTex(interface.GetPurifiedTexOnly());
123 SAX2XMLFilterImpl::characters(purifiedTex.data(), purifiedTex.size());
124 SAX2XMLFilterImpl::endElement(MathMLnamespace.c_str(), unprefixedAnnotation.c_str(), prefixedAnnotation.c_str());
125 }
126 if (annotatePNG) {
127 static XercesString PNG("image-file-PNG");
128 wstring purifiedTex = interface.GetPurifiedTex();
129 PngInfo info = MakePngFile(purifiedTex, "", pngParams);
130 AttributesImpl annotationAttributes;
131 annotationAttributes.addAttribute(encoding.c_str(), empty.c_str(), encoding.c_str(), PNG.c_str(), empty.c_str());
132 SAX2XMLFilterImpl::startElement(MathMLnamespace.c_str(), unprefixedAnnotation.c_str(), prefixedAnnotation.c_str(), annotationAttributes);
133 XercesString fileName(info.fullFileName.c_str());
134 SAX2XMLFilterImpl::characters(fileName.data(), fileName.size());
135 SAX2XMLFilterImpl::endElement(MathMLnamespace.c_str(), unprefixedAnnotation.c_str(), prefixedAnnotation.c_str());
136 }
137 SAX2XMLFilterImpl::endElement(MathMLnamespace.c_str(), unprefixedSemantics.c_str(), prefixedSemantics.c_str());
138 }
139 else
140 interface.PrintAsSAX2(*this, MathMLprefix, true);
141 if (encloseInMathTag)
142 SAX2XMLFilterImpl::endElement(MathMLnamespace.c_str(), unprefixedMath.c_str(), prefixedMath.c_str());
143 if (!MathMLexistingNamespace)
144 SAX2XMLFilterImpl::endPrefixMapping(MathMLprefix_.c_str());
145 }
146 catch (blahtex::Exception& e) {
147 wstring output = GetErrorMessage(e);
148 XercesString outputXerces(output);
149 SAX2XMLFilterImpl::startElement(uri, localname, qname, attributes);
150 SAX2XMLFilterImpl::startPrefixMapping(empty.c_str(), blahtexmlNamespace.c_str());
151 SAX2XMLFilterImpl::startElement(blahtexmlNamespace.c_str(), error.c_str(), error.c_str(), emptyAttributes);
152 SAX2XMLFilterImpl::characters(outputXerces.data(), outputXerces.length());
153 SAX2XMLFilterImpl::endElement(blahtexmlNamespace.c_str(), error.c_str(), error.c_str());
154 SAX2XMLFilterImpl::endPrefixMapping(empty.c_str());
155 numberOfErrors++;
156 }
157 }
158 else {
159 SAX2XMLFilterImpl::startElement(uri, localname, qname, attributes);
160 }
161 }
162
startPrefixMapping(const XMLCh * const prefix,const XMLCh * const uri)163 void BlahtexFilter::startPrefixMapping(const XMLCh* const prefix, const XMLCh* const uri)
164 {
165 XercesString prefixXerces(prefix), uriXerces(uri);
166 pair<wstring, wstring> context(prefixXerces.convertTowstring(), uriXerces.convertTowstring());
167 namespaceContext.push_front(context);
168 SAX2XMLFilterImpl::startPrefixMapping(prefix, uri);
169 }
170
endPrefixMapping(const XMLCh * const prefix)171 void BlahtexFilter::endPrefixMapping(const XMLCh* const prefix)
172 {
173 XercesString prefixXerces(prefix);
174 wstring prefixwstring=prefixXerces.convertTowstring();
175 for(list_wstring2::iterator i=namespaceContext.begin(); i != namespaceContext.end(); ++i) {
176 if ((*i).first == prefixwstring) {
177 namespaceContext.erase(i);
178 break;
179 }
180 }
181 SAX2XMLFilterImpl::endPrefixMapping(prefix);
182 }
183
getMathMLprefix(wstring & prefix)184 bool BlahtexFilter::getMathMLprefix(wstring& prefix)
185 {
186 for(list_wstring2::iterator i=namespaceContext.begin(); i != namespaceContext.end(); ++i) {
187 if ((*i).second == L"http://www.w3.org/1998/Math/MathML") {
188 prefix = (*i).first;
189 return true;
190 }
191 }
192 prefix = L"";
193 return false;
194 }
195
getNumberOfErrors()196 int BlahtexFilter::getNumberOfErrors()
197 {
198 return numberOfErrors;
199 }
200
setDesiredMathMLPrefixType(PrefixType aPrefixType,const wstring & aPrefix)201 void BlahtexFilter::setDesiredMathMLPrefixType(PrefixType aPrefixType, const wstring& aPrefix)
202 {
203 desiredMathMLPrefixType = aPrefixType;
204 desiredMathMLPrefix = aPrefix;
205 }
206
setAnnotatePNG(bool anAnnotatePNG)207 void BlahtexFilter::setAnnotatePNG(bool anAnnotatePNG)
208 {
209 annotatePNG = anAnnotatePNG;
210 }
211
setAnnotateTeX(bool anAnnotateTeX)212 void BlahtexFilter::setAnnotateTeX(bool anAnnotateTeX)
213 {
214 annotateTeX = anAnnotateTeX;
215 }
216
setPngParams(const PngParams & aPngParams)217 void BlahtexFilter::setPngParams(const PngParams& aPngParams)
218 {
219 pngParams = aPngParams;
220 }
221