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