1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_starmath.hxx"
26 
27 /*
28  Warning: The SvXMLElementExport helper class creates the beginning and
29  closing tags of xml elements in its constructor and destructor, so theres
30  hidden stuff going on, on occasion the ordering of these classes declarations
31  may be significant
32 */
33 
34 
35 #include <com/sun/star/xml/sax/XErrorHandler.hpp>
36 #include <com/sun/star/xml/sax/XEntityResolver.hpp>
37 #include <com/sun/star/xml/sax/InputSource.hpp>
38 #include <com/sun/star/xml/sax/XDTDHandler.hpp>
39 #include <com/sun/star/xml/sax/XParser.hpp>
40 #include <com/sun/star/io/XActiveDataSource.hpp>
41 #include <com/sun/star/io/XActiveDataControl.hpp>
42 #include <com/sun/star/document/XDocumentProperties.hpp>
43 #include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
44 #include <com/sun/star/packages/zip/ZipIOException.hpp>
45 #include <com/sun/star/task/XStatusIndicatorFactory.hpp>
46 #include <com/sun/star/beans/PropertyAttribute.hpp>
47 #include <com/sun/star/container/XNameAccess.hpp>
48 #include <com/sun/star/embed/ElementModes.hpp>
49 #include <com/sun/star/uno/Any.h>
50 
51 #include <rtl/math.hxx>
52 #include <sfx2/frame.hxx>
53 #include <sfx2/docfile.hxx>
54 #include <tools/debug.hxx>
55 #include <tools/urlobj.hxx>
56 #include <svtools/sfxecode.hxx>
57 #include <unotools/saveopt.hxx>
58 #include <svl/stritem.hxx>
59 #include <svl/itemprop.hxx>
60 #include <unotools/processfactory.hxx>
61 #include <unotools/streamwrap.hxx>
62 #include <xmloff/xmlnmspe.hxx>
63 #include <xmloff/xmltoken.hxx>
64 #include <xmloff/nmspmap.hxx>
65 #include <xmloff/attrlist.hxx>
66 #include <xmloff/xmluconv.hxx>
67 #include <xmloff/xmlmetai.hxx>
68 #include <osl/mutex.hxx>
69 #include <comphelper/genericpropertyset.hxx>
70 
71 #include <memory>
72 
73 #include "mathmlexport.hxx"
74 #include <starmath.hrc>
75 #include <unomodel.hxx>
76 #include <document.hxx>
77 #include <utility.hxx>
78 #include <config.hxx>
79 
80 using namespace ::com::sun::star::beans;
81 using namespace ::com::sun::star::container;
82 using namespace ::com::sun::star::document;
83 using namespace ::com::sun::star::lang;
84 using namespace ::com::sun::star::uno;
85 using namespace ::com::sun::star;
86 using namespace ::xmloff::token;
87 
88 using ::rtl::OUString;
89 using ::rtl::OUStringBuffer;
90 
91 #define EXPORT_SVC_NAME RTL_CONSTASCII_USTRINGPARAM("com.sun.star.xml.XMLExportFilter")
92 
93 #undef WANTEXCEPT
94 
95 
96 ////////////////////////////////////////////////////////////
97 
98 sal_Bool SmXMLExportWrapper::Export(SfxMedium &rMedium)
99 {
100     sal_Bool bRet=sal_True;
101     uno::Reference<lang::XMultiServiceFactory>
102         xServiceFactory(utl::getProcessServiceFactory());
103     DBG_ASSERT(xServiceFactory.is(),"got no service manager");
104 
105     //Get model
106     uno::Reference< lang::XComponent > xModelComp(xModel, uno::UNO_QUERY );
107 
108     sal_Bool bEmbedded = sal_False;
109     uno::Reference <lang::XUnoTunnel> xTunnel;
110     xTunnel = uno::Reference <lang::XUnoTunnel> (xModel,uno::UNO_QUERY);
111     SmModel *pModel = reinterpret_cast<SmModel *>
112         (xTunnel->getSomething(SmModel::getUnoTunnelId()));
113 
114     SmDocShell *pDocShell = pModel ?
115             static_cast<SmDocShell*>(pModel->GetObjectShell()) : 0;
116     if ( pDocShell &&
117         SFX_CREATE_MODE_EMBEDDED == pDocShell->GetCreateMode() )
118         bEmbedded = sal_True;
119 
120     uno::Reference<task::XStatusIndicator> xStatusIndicator;
121     if (!bEmbedded)
122     {
123         if (pDocShell /*&& pDocShell->GetMedium()*/)
124         {
125             DBG_ASSERT( pDocShell->GetMedium() == &rMedium,
126                     "different SfxMedium found" );
127 
128             SfxItemSet* pSet = rMedium.GetItemSet();
129             if (pSet)
130             {
131                 const SfxUnoAnyItem* pItem = static_cast<const SfxUnoAnyItem*>(
132                     pSet->GetItem(SID_PROGRESS_STATUSBAR_CONTROL) );
133                 if (pItem)
134                     pItem->GetValue() >>= xStatusIndicator;
135             }
136         }
137 
138         // set progress range and start status indicator
139         if (xStatusIndicator.is())
140         {
141             sal_Int32 nProgressRange = bFlat ? 1 : 3;
142             xStatusIndicator->start(String(SmResId(STR_STATSTR_WRITING)),
143                 nProgressRange);
144         }
145     }
146 
147 
148     // create XPropertySet with three properties for status indicator
149     comphelper::PropertyMapEntry aInfoMap[] =
150     {
151         { "UsePrettyPrinting", sizeof("UsePrettyPrinting")-1, 0,
152               &::getBooleanCppuType(),
153               beans::PropertyAttribute::MAYBEVOID, 0},
154         { "BaseURI", sizeof("BaseURI")-1, 0,
155               &::getCppuType( (OUString *)0 ),
156               beans::PropertyAttribute::MAYBEVOID, 0 },
157         { "StreamRelPath", sizeof("StreamRelPath")-1, 0,
158               &::getCppuType( (OUString *)0 ),
159               beans::PropertyAttribute::MAYBEVOID, 0 },
160         { "StreamName", sizeof("StreamName")-1, 0,
161               &::getCppuType( (OUString *)0 ),
162               beans::PropertyAttribute::MAYBEVOID, 0 },
163         { NULL, 0, 0, NULL, 0, 0 }
164     };
165     uno::Reference< beans::XPropertySet > xInfoSet(
166                 comphelper::GenericPropertySet_CreateInstance(
167                             new comphelper::PropertySetInfo( aInfoMap ) ) );
168 
169     SvtSaveOptions aSaveOpt;
170     OUString sUsePrettyPrinting(RTL_CONSTASCII_USTRINGPARAM("UsePrettyPrinting"));
171     sal_Bool bUsePrettyPrinting( bFlat || aSaveOpt.IsPrettyPrinting() );
172     Any aAny;
173     aAny.setValue( &bUsePrettyPrinting, ::getBooleanCppuType() );
174     xInfoSet->setPropertyValue( sUsePrettyPrinting, aAny );
175 
176     // Set base URI
177     OUString sPropName( RTL_CONSTASCII_USTRINGPARAM("BaseURI") );
178     xInfoSet->setPropertyValue( sPropName, makeAny( rMedium.GetBaseURL( true ) ) );
179 
180     sal_Int32 nSteps=0;
181     if (xStatusIndicator.is())
182             xStatusIndicator->setValue(nSteps++);
183     if (!bFlat) //Storage (Package) of Stream
184     {
185         uno::Reference < embed::XStorage > xStg = rMedium.GetOutputStorage();
186         sal_Bool bOASIS = ( SotStorage::GetVersion( xStg ) > SOFFICE_FILEFORMAT_60 );
187 
188         // TODO/LATER: handle the case of embedded links gracefully
189         if ( bEmbedded ) //&& !pStg->IsRoot() )
190         {
191             OUString aName;
192             if ( rMedium.GetItemSet() )
193             {
194                 const SfxStringItem* pDocHierarchItem = static_cast<const SfxStringItem*>(
195                     rMedium.GetItemSet()->GetItem(SID_DOC_HIERARCHICALNAME) );
196                 if ( pDocHierarchItem )
197                     aName = pDocHierarchItem->GetValue();
198             }
199 
200             if ( aName.getLength() )
201             {
202                 sPropName = OUString(RTL_CONSTASCII_USTRINGPARAM("StreamRelPath"));
203                 xInfoSet->setPropertyValue( sPropName, makeAny( aName ) );
204             }
205         }
206 
207         if ( !bEmbedded )
208         {
209             if (xStatusIndicator.is())
210                 xStatusIndicator->setValue(nSteps++);
211 
212             bRet = WriteThroughComponent(
213                     xStg, xModelComp, "meta.xml", xServiceFactory, xInfoSet,
214                     (bOASIS ? "com.sun.star.comp.Math.XMLOasisMetaExporter"
215                             : "com.sun.star.comp.Math.XMLMetaExporter"),
216                     sal_False);
217         }
218         if ( bRet )
219         {
220            if (xStatusIndicator.is())
221                 xStatusIndicator->setValue(nSteps++);
222 
223             bRet = WriteThroughComponent(
224                     xStg, xModelComp, "content.xml", xServiceFactory, xInfoSet,
225                     "com.sun.star.comp.Math.XMLContentExporter");
226         }
227 
228         if ( bRet )
229         {
230             if (xStatusIndicator.is())
231                 xStatusIndicator->setValue(nSteps++);
232 
233             bRet = WriteThroughComponent(
234                     xStg, xModelComp, "settings.xml", xServiceFactory, xInfoSet,
235                     (bOASIS ? "com.sun.star.comp.Math.XMLOasisSettingsExporter"
236                             : "com.sun.star.comp.Math.XMLSettingsExporter") );
237         }
238     }
239     else
240     {
241         SvStream *pStream = rMedium.GetOutStream();
242         uno::Reference<io::XOutputStream> xOut(
243             new utl::OOutputStreamWrapper(*pStream) );
244 
245         if (xStatusIndicator.is())
246             xStatusIndicator->setValue(nSteps++);
247 
248         bRet = WriteThroughComponent(
249             xOut, xModelComp, xServiceFactory, xInfoSet,
250             "com.sun.star.comp.Math.XMLContentExporter");
251     }
252 
253     if (xStatusIndicator.is())
254         xStatusIndicator->end();
255 
256     return bRet;
257 }
258 
259 
260 /// export through an XML exporter component (output stream version)
261 sal_Bool SmXMLExportWrapper::WriteThroughComponent(
262     Reference<io::XOutputStream> xOutputStream,
263     Reference<XComponent> xComponent,
264     Reference<lang::XMultiServiceFactory> & rFactory,
265     Reference<beans::XPropertySet> & rPropSet,
266     const sal_Char* pComponentName )
267 {
268     DBG_ASSERT(xOutputStream.is(), "I really need an output stream!");
269     DBG_ASSERT(xComponent.is(), "Need component!");
270     DBG_ASSERT(NULL != pComponentName, "Need component name!");
271 
272     // get component
273     Reference< io::XActiveDataSource > xSaxWriter(
274         rFactory->createInstance(
275             OUString::createFromAscii("com.sun.star.xml.sax.Writer") ),
276         UNO_QUERY );
277     DBG_ASSERT( xSaxWriter.is(), "can't instantiate XML writer" );
278     if (!xSaxWriter.is())
279         return sal_False;
280 
281     // connect XML writer to output stream
282     xSaxWriter->setOutputStream( xOutputStream );
283 
284     // prepare arguments (prepend doc handler to given arguments)
285     Reference<xml::sax::XDocumentHandler> xDocHandler( xSaxWriter,UNO_QUERY);
286 
287     Sequence<Any> aArgs( 2 );
288     aArgs[0] <<= xDocHandler;
289     aArgs[1] <<= rPropSet;
290 
291     // get filter component
292     Reference< document::XExporter > xExporter(
293         rFactory->createInstanceWithArguments(
294             OUString::createFromAscii(pComponentName), aArgs), UNO_QUERY);
295     DBG_ASSERT( xExporter.is(),
296             "can't instantiate export filter component" );
297     if ( !xExporter.is() )
298         return sal_False;
299 
300 
301     // connect model and filter
302     xExporter->setSourceDocument( xComponent );
303 
304     // filter!
305     Reference < XFilter > xFilter( xExporter, UNO_QUERY );
306     uno::Sequence< PropertyValue > aProps(0);
307     xFilter->filter( aProps );
308 
309     uno::Reference<lang::XUnoTunnel> xFilterTunnel;
310     xFilterTunnel = uno::Reference<lang::XUnoTunnel>
311         ( xFilter, uno::UNO_QUERY );
312     SmXMLExport *pFilter = reinterpret_cast< SmXMLExport * >(
313                 sal::static_int_cast< sal_uIntPtr >(
314                 xFilterTunnel->getSomething( SmXMLExport::getUnoTunnelId() )));
315     return pFilter ? pFilter->GetSuccess() : sal_True;
316 }
317 
318 
319 /// export through an XML exporter component (storage version)
320 sal_Bool SmXMLExportWrapper::WriteThroughComponent(
321     const Reference < embed::XStorage >& xStorage,
322     Reference<XComponent> xComponent,
323     const sal_Char* pStreamName,
324     Reference<lang::XMultiServiceFactory> & rFactory,
325     Reference<beans::XPropertySet> & rPropSet,
326     const sal_Char* pComponentName,
327     sal_Bool bCompress
328     )
329 {
330     DBG_ASSERT(xStorage.is(), "Need storage!");
331     DBG_ASSERT(NULL != pStreamName, "Need stream name!");
332 
333     // open stream
334     Reference < io::XStream > xStream;
335     OUString sStreamName = OUString::createFromAscii(pStreamName);
336     try
337     {
338         xStream = xStorage->openStreamElement( sStreamName,
339             embed::ElementModes::READWRITE | embed::ElementModes::TRUNCATE );
340     }
341     catch ( uno::Exception& )
342     {
343         DBG_ERROR( "Can't create output stream in package!" );
344         return sal_False;
345     }
346 
347     String aPropName( String::CreateFromAscii( RTL_CONSTASCII_STRINGPARAM("MediaType") ) );
348     OUString aMime( RTL_CONSTASCII_USTRINGPARAM("text/xml") );
349     uno::Any aAny;
350     aAny <<= aMime;
351 
352     uno::Reference < beans::XPropertySet > xSet( xStream, uno::UNO_QUERY );
353     xSet->setPropertyValue( aPropName, aAny );
354 
355     if ( !bCompress )
356     {
357         aPropName = String::CreateFromAscii( RTL_CONSTASCII_STRINGPARAM("Compressed") );
358         sal_Bool bFalse = sal_False;
359         aAny.setValue( &bFalse, ::getBooleanCppuType() );
360         xSet->setPropertyValue( aPropName, aAny );
361     }
362 
363     // even plain stream must be encrypted in encrypted document
364     OUString aTmpPropName( RTL_CONSTASCII_USTRINGPARAM("UseCommonStoragePasswordEncryption") );
365     sal_Bool bTrue = sal_True;
366     aAny.setValue( &bTrue, ::getBooleanCppuType() );
367     xSet->setPropertyValue( aTmpPropName, aAny );
368 
369     // set Base URL
370     if ( rPropSet.is() )
371     {
372         OUString sPropName( RTL_CONSTASCII_USTRINGPARAM("StreamName") );
373         rPropSet->setPropertyValue( sPropName, makeAny( sStreamName ) );
374     }
375 
376     // write the stuff
377     sal_Bool bRet = WriteThroughComponent( xStream->getOutputStream(), xComponent, rFactory,
378         rPropSet, pComponentName );
379 
380     // stream is closed by SAX parser
381     //if ( bRet )
382     //    xStream->getOutputStream()->closeOutput();
383 
384     return bRet;
385 }
386 
387 ////////////////////////////////////////////////////////////
388 
389 // #110680#
390 SmXMLExport::SmXMLExport(
391     const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > xServiceFactory,
392     sal_uInt16 nExportFlags)
393 :   SvXMLExport( xServiceFactory, MAP_INCH, XML_MATH, nExportFlags ) ,
394     pTree(0) ,
395     bSuccess(sal_False)
396 {
397 }
398 
399 sal_Int64 SAL_CALL SmXMLExport::getSomething(
400     const uno::Sequence< sal_Int8 >& rId )
401 throw(uno::RuntimeException)
402 {
403     if ( rId.getLength() == 16 &&
404         0 == rtl_compareMemory( getUnoTunnelId().getConstArray(),
405         rId.getConstArray(), 16 ) )
406     return sal::static_int_cast< sal_Int64 >(reinterpret_cast< sal_uIntPtr >(this));
407 
408     return SvXMLExport::getSomething( rId );
409 }
410 
411 const uno::Sequence< sal_Int8 > & SmXMLExport::getUnoTunnelId() throw()
412 {
413     static uno::Sequence< sal_Int8 > * pSeq = 0;
414     if ( !pSeq )
415     {
416         osl::Guard< osl::Mutex > aGuard( osl::Mutex::getGlobalMutex() );
417         if ( !pSeq )
418         {
419             static uno::Sequence< sal_Int8 > aSeq( 16 );
420             rtl_createUuid( (sal_uInt8*)aSeq.getArray(), 0, sal_True );
421             pSeq = &aSeq;
422         }
423     }
424     return *pSeq;
425 }
426 
427 OUString SAL_CALL SmXMLExport_getImplementationName() throw()
428 {
429     return OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.comp.Math.XMLExporter" ) );
430 }
431 
432 uno::Sequence< OUString > SAL_CALL SmXMLExport_getSupportedServiceNames()
433         throw()
434 {
435     const OUString aServiceName( EXPORT_SVC_NAME );
436     const uno::Sequence< OUString > aSeq( &aServiceName, 1 );
437     return aSeq;
438 }
439 
440 uno::Reference< uno::XInterface > SAL_CALL SmXMLExport_createInstance(
441     const uno::Reference< lang::XMultiServiceFactory > & rSMgr)
442     throw( uno::Exception )
443 {
444     // #110680#
445     // return (cppu::OWeakObject*)new SmXMLExport( EXPORT_ALL );
446     // EXPORT_OASIS is required here although there is no differrence between
447     // OOo and OASIS, because without the flag, a transformation to OOo would
448     // be chained in.
449     return (cppu::OWeakObject*)new SmXMLExport( rSMgr, EXPORT_OASIS|EXPORT_ALL );
450 }
451 
452 ////////////////////////////////////////////////////////////
453 
454 OUString SAL_CALL SmXMLExportMetaOOO_getImplementationName() throw()
455 {
456     return OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.comp.Math.XMLMetaExporter" ) );
457 }
458 
459 uno::Sequence< OUString > SAL_CALL SmXMLExportMetaOOO_getSupportedServiceNames()
460     throw()
461 {
462     const OUString aServiceName( EXPORT_SVC_NAME );
463     const uno::Sequence< OUString > aSeq( &aServiceName, 1 );
464     return aSeq;
465 }
466 
467 uno::Reference< uno::XInterface > SAL_CALL SmXMLExportMetaOOO_createInstance(
468     const uno::Reference< lang::XMultiServiceFactory > & rSMgr)
469 throw( uno::Exception )
470 {
471     // #110680#
472     // return (cppu::OWeakObject*)new SmXMLExport( EXPORT_META );
473     return (cppu::OWeakObject*)new SmXMLExport( rSMgr, EXPORT_META );
474 }
475 
476 ////////////////////////////////////////////////////////////
477 
478 OUString SAL_CALL SmXMLExportMeta_getImplementationName() throw()
479 {
480     return OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.comp.Math.XMLOasisMetaExporter" ) );
481 }
482 
483 uno::Sequence< OUString > SAL_CALL SmXMLExportMeta_getSupportedServiceNames()
484 throw()
485 {
486     const OUString aServiceName( EXPORT_SVC_NAME );
487     const uno::Sequence< OUString > aSeq( &aServiceName, 1 );
488     return aSeq;
489 }
490 
491 uno::Reference< uno::XInterface > SAL_CALL SmXMLExportMeta_createInstance(
492     const uno::Reference< lang::XMultiServiceFactory > & rSMgr)
493 throw( uno::Exception )
494 {
495     // #110680#
496     // return (cppu::OWeakObject*)new SmXMLExport( EXPORT_META );
497     return (cppu::OWeakObject*)new SmXMLExport( rSMgr, EXPORT_OASIS|EXPORT_META );
498 }
499 
500 ////////////////////////////////////////////////////////////
501 
502 OUString SAL_CALL SmXMLExportSettingsOOO_getImplementationName() throw()
503 {
504     return OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.comp.Math.XMLSettingsExporter" ) );
505 }
506 
507 uno::Sequence< OUString > SAL_CALL SmXMLExportSettingsOOO_getSupportedServiceNames()
508 throw()
509 {
510     const OUString aServiceName( EXPORT_SVC_NAME );
511     const uno::Sequence< OUString > aSeq( &aServiceName, 1 );
512     return aSeq;
513 }
514 
515 uno::Reference< uno::XInterface > SAL_CALL SmXMLExportSettingsOOO_createInstance(
516     const uno::Reference< lang::XMultiServiceFactory > & rSMgr)
517 throw( uno::Exception )
518 {
519     // #110680#
520     // return (cppu::OWeakObject*)new SmXMLExport( EXPORT_SETTINGS );
521     return (cppu::OWeakObject*)new SmXMLExport( rSMgr, EXPORT_SETTINGS );
522 }
523 
524 ////////////////////////////////////////////////////////////
525 
526 OUString SAL_CALL SmXMLExportSettings_getImplementationName() throw()
527 {
528     return OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.comp.Math.XMLOasisSettingsExporter" ) );
529 }
530 
531 uno::Sequence< OUString > SAL_CALL SmXMLExportSettings_getSupportedServiceNames()
532 throw()
533 {
534     const OUString aServiceName( EXPORT_SVC_NAME );
535     const uno::Sequence< OUString > aSeq( &aServiceName, 1 );
536     return aSeq;
537 }
538 
539 uno::Reference< uno::XInterface > SAL_CALL SmXMLExportSettings_createInstance(
540     const uno::Reference< lang::XMultiServiceFactory > & rSMgr)
541 throw( uno::Exception )
542 {
543     // #110680#
544     // return (cppu::OWeakObject*)new SmXMLExport( EXPORT_SETTINGS );
545     return (cppu::OWeakObject*)new SmXMLExport( rSMgr, EXPORT_OASIS|EXPORT_SETTINGS );
546 }
547 
548 ////////////////////////////////////////////////////////////
549 
550 OUString SAL_CALL SmXMLExportContent_getImplementationName() throw()
551 {
552     return OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.comp.Math.XMLContentExporter" ) );
553 }
554 
555 uno::Sequence< OUString > SAL_CALL SmXMLExportContent_getSupportedServiceNames()
556         throw()
557 {
558     const OUString aServiceName( EXPORT_SVC_NAME );
559     const uno::Sequence< OUString > aSeq( &aServiceName, 1 );
560     return aSeq;
561 }
562 
563 uno::Reference< uno::XInterface > SAL_CALL SmXMLExportContent_createInstance(
564     const uno::Reference< lang::XMultiServiceFactory > & rSMgr)
565 throw( uno::Exception )
566 {
567     // #110680#
568     // return (cppu::OWeakObject*)new SmXMLExport( EXPORT_CONTENT );
569     // The EXPORT_OASIS flag is only required to avoid that a transformer is
570     // chanied in
571     return (cppu::OWeakObject*)new SmXMLExport( rSMgr, EXPORT_OASIS|EXPORT_CONTENT );
572 }
573 
574 ////////////////////////////////////////////////////////////
575 
576 // XServiceInfo
577 // override empty method from parent class
578 rtl::OUString SAL_CALL SmXMLExport::getImplementationName()
579 throw(uno::RuntimeException)
580 {
581     OUString aTxt;
582     switch( getExportFlags() )
583     {
584         case EXPORT_META:
585             aTxt = SmXMLExportMeta_getImplementationName();
586             break;
587         case EXPORT_SETTINGS:
588             aTxt = SmXMLExportSettings_getImplementationName();
589             break;
590         case EXPORT_CONTENT:
591             aTxt = SmXMLExportContent_getImplementationName();
592             break;
593         case EXPORT_ALL:
594         default:
595             aTxt = SmXMLExport_getImplementationName();
596             break;
597     }
598     return aTxt;
599 }
600 
601 sal_uInt32 SmXMLExport::exportDoc(enum XMLTokenEnum eClass)
602 {
603     if ( (getExportFlags() & EXPORT_CONTENT) == 0 )
604     {
605         SvXMLExport::exportDoc( eClass );
606     }
607     else
608     {
609         uno::Reference <frame::XModel> xModel = GetModel();
610         uno::Reference <lang::XUnoTunnel> xTunnel;
611         xTunnel = uno::Reference <lang::XUnoTunnel> (xModel,uno::UNO_QUERY);
612         SmModel *pModel = reinterpret_cast<SmModel *>
613             (xTunnel->getSomething(SmModel::getUnoTunnelId()));
614 
615         if (pModel)
616         {
617             SmDocShell *pDocShell =
618                 static_cast<SmDocShell*>(pModel->GetObjectShell());
619             pTree = pDocShell->GetFormulaTree();
620             aText = pDocShell->GetText();
621         }
622 
623         GetDocHandler()->startDocument();
624 
625         /*Add xmlns line*/
626         SvXMLAttributeList &rList = GetAttrList();
627 
628         // make use of a default namespace
629         ResetNamespaceMap();    // Math doesn't need namespaces from xmloff, since it now uses default namespaces (because that is common with current MathML usage in the web)
630         _GetNamespaceMap().Add( OUString::createFromAscii(""), GetXMLToken(XML_N_MATH), XML_NAMESPACE_MATH );
631 
632         rList.AddAttribute(GetNamespaceMap().GetAttrNameByKey(XML_NAMESPACE_MATH_IDX),
633                 GetNamespaceMap().GetNameByKey( XML_NAMESPACE_MATH_IDX));
634 
635         //I think we need something like ImplExportEntities();
636         _ExportContent();
637         GetDocHandler()->endDocument();
638     }
639 
640     bSuccess=sal_True;
641     return 0;
642 }
643 
644 void SmXMLExport::_ExportContent()
645 {
646     SvXMLElementExport aEquation(*this, XML_NAMESPACE_MATH, XML_MATH, sal_True, sal_True);
647     SvXMLElementExport *pSemantics=0;
648 
649     if (aText.Len())
650     {
651         pSemantics = new SvXMLElementExport(*this, XML_NAMESPACE_MATH,
652             XML_SEMANTICS, sal_True, sal_True);
653     }
654 
655     ExportNodes(pTree, 0);
656 
657     if (aText.Len())
658     {
659         // Convert symbol names
660         uno::Reference <frame::XModel> xModel = GetModel();
661         uno::Reference <lang::XUnoTunnel> xTunnel;
662         xTunnel = uno::Reference <lang::XUnoTunnel> (xModel,uno::UNO_QUERY);
663         SmModel *pModel = reinterpret_cast<SmModel *>
664             (xTunnel->getSomething(SmModel::getUnoTunnelId()));
665         SmDocShell *pDocShell = pModel ?
666             static_cast<SmDocShell*>(pModel->GetObjectShell()) : 0;
667         DBG_ASSERT( pDocShell, "doc shell missing" );
668         if (pDocShell)
669         {
670             SmParser &rParser = pDocShell->GetParser();
671             sal_Bool bVal = rParser.IsExportSymbolNames();
672             rParser.SetExportSymbolNames( sal_True );
673             SmNode *pTmpTree = rParser.Parse( aText );
674             aText = rParser.GetText();
675             delete pTmpTree;
676             rParser.SetExportSymbolNames( bVal );
677         }
678 
679         AddAttribute(XML_NAMESPACE_MATH, XML_ENCODING,
680             OUString(RTL_CONSTASCII_USTRINGPARAM("StarMath 5.0")));
681         SvXMLElementExport aAnnotation(*this, XML_NAMESPACE_MATH,
682             XML_ANNOTATION, sal_True, sal_False);
683         GetDocHandler()->characters(OUString( aText ));
684     }
685     delete pSemantics;
686 }
687 
688 void SmXMLExport::GetViewSettings( Sequence < PropertyValue >& aProps)
689 {
690     uno::Reference <frame::XModel> xModel = GetModel();
691     if ( !xModel.is() )
692         return;
693 
694     uno::Reference <lang::XUnoTunnel> xTunnel;
695     xTunnel = uno::Reference <lang::XUnoTunnel> (xModel,uno::UNO_QUERY);
696     SmModel *pModel = reinterpret_cast<SmModel *>
697         (xTunnel->getSomething(SmModel::getUnoTunnelId()));
698 
699     if ( !pModel )
700         return;
701 
702     SmDocShell *pDocShell =
703         static_cast<SmDocShell*>(pModel->GetObjectShell());
704     if ( !pDocShell )
705         return;
706 
707     aProps.realloc( 4 );
708     PropertyValue *pValue = aProps.getArray();
709     sal_Int32 nIndex = 0;
710 
711     Rectangle aRect( pDocShell->GetVisArea() );
712 
713     pValue[nIndex].Name = OUString( RTL_CONSTASCII_USTRINGPARAM ( "ViewAreaTop") );
714     pValue[nIndex++].Value <<= aRect.Top();
715 
716     pValue[nIndex].Name = OUString( RTL_CONSTASCII_USTRINGPARAM ( "ViewAreaLeft") );
717     pValue[nIndex++].Value <<= aRect.Left();
718 
719     pValue[nIndex].Name = OUString( RTL_CONSTASCII_USTRINGPARAM ( "ViewAreaWidth") );
720     pValue[nIndex++].Value <<= aRect.GetWidth();
721 
722     pValue[nIndex].Name = OUString( RTL_CONSTASCII_USTRINGPARAM ( "ViewAreaHeight") );
723     pValue[nIndex++].Value <<= aRect.GetHeight();
724 }
725 
726 void SmXMLExport::GetConfigurationSettings( Sequence < PropertyValue > & rProps)
727 {
728     Reference < XPropertySet > xProps ( GetModel(), UNO_QUERY );
729     if ( xProps.is() )
730     {
731         Reference< XPropertySetInfo > xPropertySetInfo = xProps->getPropertySetInfo();
732         if (xPropertySetInfo.is())
733         {
734             Sequence< Property > aProps = xPropertySetInfo->getProperties();
735             sal_Int32 nCount(aProps.getLength());
736             if (nCount > 0)
737             {
738                 rProps.realloc(nCount);
739                 PropertyValue* pProps = rProps.getArray();
740                 if (pProps)
741                 {
742                     SmConfig *pConfig = SM_MOD()->GetConfig();
743                     const bool bUsedSymbolsOnly = pConfig ? pConfig->IsSaveOnlyUsedSymbols() : false;
744 
745                     const OUString sFormula ( RTL_CONSTASCII_USTRINGPARAM ( "Formula" ) );
746                     const OUString sBasicLibraries ( RTL_CONSTASCII_USTRINGPARAM ( "BasicLibraries" ) );
747                     const OUString sDialogLibraries ( RTL_CONSTASCII_USTRINGPARAM ( "DialogLibraries" ) );
748                     const OUString sRuntimeUID ( RTL_CONSTASCII_USTRINGPARAM ( "RuntimeUID" ) );
749                     for (sal_Int32 i = 0; i < nCount; i++, pProps++)
750                     {
751                         const OUString &rPropName = aProps[i].Name;
752                         if (rPropName != sFormula &&
753                             rPropName != sBasicLibraries &&
754                             rPropName != sDialogLibraries &&
755                             rPropName != sRuntimeUID)
756                         {
757                             pProps->Name = rPropName;
758 
759                             rtl::OUString aActualName( rPropName );
760 
761                             // handle 'save used symbols only'
762                             if (bUsedSymbolsOnly && rPropName.equalsAscii("Symbols"))
763                                 aActualName = OUString( RTL_CONSTASCII_USTRINGPARAM ( "UserDefinedSymbolsInUse" ) );
764 
765                             pProps->Value = xProps->getPropertyValue( aActualName );
766                         }
767                     }
768                 }
769             }
770         }
771     }
772 }
773 
774 void SmXMLExport::ExportLine(const SmNode *pNode, int nLevel)
775 {
776     ExportExpression(pNode, nLevel);
777 }
778 
779 void SmXMLExport::ExportBinaryHorizontal(const SmNode *pNode, int nLevel)
780 {
781     ExportExpression(pNode, nLevel);
782 }
783 
784 void SmXMLExport::ExportUnaryHorizontal(const SmNode *pNode, int nLevel)
785 {
786     ExportExpression(pNode, nLevel);
787 }
788 
789 void SmXMLExport::ExportExpression(const SmNode *pNode, int nLevel)
790 {
791     SvXMLElementExport *pRow=0;
792     sal_uLong  nSize = pNode->GetNumSubNodes();
793 
794     // #i115443: nodes of type expression always need to be grouped with mrow statement
795     if (nSize > 1 || (pNode && pNode->GetType() == NEXPRESSION))
796         pRow = new SvXMLElementExport(*this, XML_NAMESPACE_MATH, XML_MROW, sal_True, sal_True);
797 
798     //if (nSize)
799     //{
800         for (sal_uInt16 i = 0; i < nSize; i++)
801             if (const SmNode *pTemp = pNode->GetSubNode(i))
802                 ExportNodes(pTemp, nLevel+1);
803     //}
804 #if 0
805     else
806     {
807         //This saves us from situations like "a newline" where the
808         //lack of a term following the newline would otherwise create
809         //a incorrect token like <mtr/>
810         SvXMLElementExport aDummy(*this, XML_NAMESPACE_MATH, XML_MI, sal_True, sal_False);
811         sal_Unicode nArse[2] = {'\n','\0'};
812         GetDocHandler()->characters(nArse);
813     }
814 #endif
815 
816     delete pRow;
817 }
818 
819 void SmXMLExport::ExportBinaryVertical(const SmNode *pNode, int nLevel)
820 {
821     DBG_ASSERT(pNode->GetNumSubNodes()==3,"Bad Fraction");
822     SvXMLElementExport aFraction(*this, XML_NAMESPACE_MATH, XML_MFRAC, sal_True, sal_True);
823     ExportNodes(pNode->GetSubNode(0), nLevel);
824     ExportNodes(pNode->GetSubNode(2), nLevel);
825 }
826 
827 void SmXMLExport::ExportTable(const SmNode *pNode, int nLevel)
828 {
829     SvXMLElementExport *pTable=0;
830 
831     sal_uInt16 nSize = pNode->GetNumSubNodes();
832 
833     //If the list ends in newline then the last entry has
834     //no subnodes, the newline is superfulous so we just drop
835     //the last node, inclusion would create a bad MathML
836     //table
837     if (nSize >= 1 && pNode->GetSubNode(nSize-1)->GetNumSubNodes() == 0)
838         --nSize;
839 
840     // try to avoid creating a mtable element when the formula consists only
841     // of a single output line
842     if (nLevel || (nSize >1))
843         pTable = new SvXMLElementExport(*this, XML_NAMESPACE_MATH, XML_MTABLE, sal_True, sal_True);
844 
845     for (sal_uInt16 i = 0; i < nSize; i++)
846         if (const SmNode *pTemp = pNode->GetSubNode(i))
847         {
848             SvXMLElementExport *pRow=0;
849             SvXMLElementExport *pCell=0;
850             if (pTable)
851             {
852                 pRow  = new SvXMLElementExport(*this, XML_NAMESPACE_MATH, XML_MTR, sal_True, sal_True);
853                 pCell = new SvXMLElementExport(*this, XML_NAMESPACE_MATH, XML_MTD, sal_True, sal_True);
854             }
855             ExportNodes(pTemp, nLevel+1);
856             delete pCell;
857             delete pRow;
858         }
859 
860     delete pTable;
861 }
862 
863 void SmXMLExport::ExportMath(const SmNode *pNode, int /*nLevel*/)
864 {
865     const SmMathSymbolNode *pTemp = static_cast<const SmMathSymbolNode *>(pNode);
866     SvXMLElementExport aMath(*this, XML_NAMESPACE_MATH, XML_MO, sal_True, sal_False);
867     sal_Unicode nArse[2];
868     nArse[0] = pTemp->GetText().GetChar(0);
869     sal_Unicode cTmp = ConvertMathToMathML( nArse[0] );
870     if (cTmp != 0)
871         nArse[0] = cTmp;
872     DBG_ASSERT(nArse[0] != 0xffff,"Non existent symbol");
873     nArse[1] = 0;
874     GetDocHandler()->characters(nArse);
875 }
876 
877 void SmXMLExport::ExportText(const SmNode *pNode, int /*nLevel*/)
878 {
879     SvXMLElementExport *pText;
880     const SmTextNode *pTemp = static_cast<const SmTextNode *>(pNode);
881     switch (pNode->GetToken().eType)
882     {
883         default:
884         case TIDENT:
885         {
886             //Note that we change the fontstyle to italic for strings that
887             //are italic and longer than a single character.
888             sal_Bool bIsItalic = IsItalic( pTemp->GetFont() );
889             if ((pTemp->GetText().Len() > 1) && bIsItalic)
890                 AddAttribute(XML_NAMESPACE_MATH, XML_MATHVARIANT, XML_ITALIC);
891             else if ((pTemp->GetText().Len() == 1) && !bIsItalic)
892                 AddAttribute(XML_NAMESPACE_MATH, XML_MATHVARIANT, XML_NORMAL);
893             pText = new SvXMLElementExport(*this, XML_NAMESPACE_MATH, XML_MI,sal_True,sal_False);
894             break;
895         }
896         case TNUMBER:
897             pText = new SvXMLElementExport(*this, XML_NAMESPACE_MATH, XML_MN,sal_True,sal_False);
898             break;
899         case TTEXT:
900             pText = new SvXMLElementExport(*this, XML_NAMESPACE_MATH, XML_MTEXT,sal_True,sal_False);
901             break;
902         }
903     GetDocHandler()->characters(OUString(pTemp->GetText().GetBuffer()));
904     delete pText;
905 }
906 
907 void SmXMLExport::ExportBlank(const SmNode * /*pNode*/, int /*nLevel*/)
908 {
909     //!! exports an empty <mi> tag since for example "~_~" is allowed in
910     //!! Math (so it has no sense at all) but must not result in an empty
911     //!! <msub> tag in MathML !!
912 
913     SvXMLElementExport *pText;
914     //const SmBlankNode *pTemp = static_cast<const SmBlankNode *>(pNode);
915 
916     pText = new SvXMLElementExport(*this, XML_NAMESPACE_MATH, XML_MI, sal_True, sal_False);
917 
918     GetDocHandler()->characters( OUString() );
919     delete pText;
920 }
921 
922 void SmXMLExport::ExportSubSupScript(const SmNode *pNode, int nLevel)
923 {
924     const SmNode *pSub  = 0;
925     const SmNode *pSup  = 0;
926     const SmNode *pCSub = 0;
927     const SmNode *pCSup = 0;
928     const SmNode *pLSub = 0;
929     const SmNode *pLSup = 0;
930     SvXMLElementExport *pThing = 0, *pThing2 = 0;
931 
932     //if we have prescripts at all then we must use the tensor notation
933 
934     //This is one of those excellent locations where scope is vital to
935     //arrange the construction and destruction of the element helper
936     //classes correctly
937     pLSub = pNode->GetSubNode(LSUB+1);
938     pLSup = pNode->GetSubNode(LSUP+1);
939     if (pLSub || pLSup)
940     {
941         SvXMLElementExport aMultiScripts(*this, XML_NAMESPACE_MATH,
942             XML_MMULTISCRIPTS, sal_True, sal_True);
943 
944 
945         if (NULL != (pCSub = pNode->GetSubNode(CSUB+1))
946             && NULL != (pCSup = pNode->GetSubNode(CSUP+1)))
947         {
948             pThing2 = new SvXMLElementExport(*this, XML_NAMESPACE_MATH,
949                 XML_MUNDEROVER, sal_True,sal_True);
950         }
951         else if (NULL != (pCSub = pNode->GetSubNode(CSUB+1)))
952         {
953             pThing2 = new SvXMLElementExport(*this, XML_NAMESPACE_MATH,
954                 XML_MUNDER, sal_True,sal_True);
955         }
956         else if (NULL != (pCSup = pNode->GetSubNode(CSUP+1)))
957         {
958             pThing2 = new SvXMLElementExport(*this, XML_NAMESPACE_MATH,
959                 XML_MOVER, sal_True,sal_True);
960         }
961 
962         ExportNodes(pNode->GetSubNode(0), nLevel+1);    //Main Term
963 
964         if (pCSub)
965             ExportNodes(pCSub, nLevel+1);
966         if (pCSup)
967             ExportNodes(pCSup, nLevel+1);
968         delete pThing2;
969 
970         pSub = pNode->GetSubNode(RSUB+1);
971         pSup = pNode->GetSubNode(RSUP+1);
972         if (pSub || pSup)
973         {
974             if (pSub)
975                 ExportNodes(pSub, nLevel+1);
976             else
977             {
978                 SvXMLElementExport aNone(*this, XML_NAMESPACE_MATH, XML_NONE,sal_True,sal_True);
979             }
980             if (pSup)
981                 ExportNodes(pSup, nLevel+1);
982             else
983             {
984                 SvXMLElementExport aNone(*this, XML_NAMESPACE_MATH, XML_NONE,sal_True,sal_True);
985             }
986         }
987 
988         //Seperator element between suffix and prefix sub/sup pairs
989         {
990             SvXMLElementExport aPrescripts(*this, XML_NAMESPACE_MATH,
991                 XML_MPRESCRIPTS, sal_True,sal_True);
992         }
993 
994         if (pLSub)
995             ExportNodes(pLSub, nLevel+1);
996         else
997         {
998             SvXMLElementExport aNone(*this, XML_NAMESPACE_MATH, XML_NONE,
999                 sal_True,sal_True);
1000 
1001         }
1002         if (pLSup)
1003             ExportNodes(pLSup, nLevel+1);
1004         else
1005         {
1006             SvXMLElementExport aNone(*this, XML_NAMESPACE_MATH, XML_NONE,
1007                 sal_True,sal_True);
1008 
1009         }
1010     }
1011     else
1012     {
1013         if (NULL != (pSub = pNode->GetSubNode(RSUB+1)) &&
1014             NULL != (pSup = pNode->GetSubNode(RSUP+1)))
1015         {
1016             pThing = new SvXMLElementExport(*this, XML_NAMESPACE_MATH,
1017                 XML_MSUBSUP, sal_True,sal_True);
1018         }
1019         else if (NULL != (pSub = pNode->GetSubNode(RSUB+1)))
1020         {
1021             pThing = new SvXMLElementExport(*this, XML_NAMESPACE_MATH, XML_MSUB,
1022                 sal_True,sal_True);
1023         }
1024         else if (NULL != (pSup = pNode->GetSubNode(RSUP+1)))
1025         {
1026             pThing = new SvXMLElementExport(*this, XML_NAMESPACE_MATH, XML_MSUP,
1027                 sal_True,sal_True);
1028         }
1029 
1030         if (NULL != (pCSub = pNode->GetSubNode(CSUB+1))
1031             && NULL != (pCSup=pNode->GetSubNode(CSUP+1)))
1032         {
1033             pThing2 = new SvXMLElementExport(*this, XML_NAMESPACE_MATH,
1034                 XML_MUNDEROVER, sal_True,sal_True);
1035         }
1036         else if (NULL != (pCSub = pNode->GetSubNode(CSUB+1)))
1037         {
1038             pThing2 = new SvXMLElementExport(*this, XML_NAMESPACE_MATH,
1039                 XML_MUNDER, sal_True,sal_True);
1040         }
1041         else if (NULL != (pCSup = pNode->GetSubNode(CSUP+1)))
1042         {
1043             pThing2 = new SvXMLElementExport(*this, XML_NAMESPACE_MATH,
1044                 XML_MOVER, sal_True,sal_True);
1045         }
1046         ExportNodes(pNode->GetSubNode(0), nLevel+1);    //Main Term
1047 
1048         if (pCSub)
1049             ExportNodes(pCSub, nLevel+1);
1050         if (pCSup)
1051             ExportNodes(pCSup, nLevel+1);
1052         delete pThing2;
1053 
1054         if (pSub)
1055             ExportNodes(pSub, nLevel+1);
1056         if (pSup)
1057             ExportNodes(pSup, nLevel+1);
1058         delete pThing;
1059     }
1060 }
1061 
1062 void SmXMLExport::ExportBrace(const SmNode *pNode, int nLevel)
1063 {
1064     const SmNode *pTemp;
1065     const SmNode *pLeft=pNode->GetSubNode(0);
1066     const SmNode *pRight=pNode->GetSubNode(2);
1067     SvXMLElementExport *pFences=0,*pRow=0;
1068     if ( ((pLeft) && (pLeft->GetToken().eType != TNONE)) &&
1069         ((pRight) && (pRight->GetToken().eType != TNONE)) &&
1070         (pNode->GetScaleMode() == SCALE_HEIGHT))
1071     {
1072         sal_Unicode nArse[2];
1073         nArse[1] = 0;
1074         nArse[0] = static_cast<
1075             const SmMathSymbolNode* >(pLeft)->GetText().GetChar(0);
1076         DBG_ASSERT(nArse[0] != 0xffff,"Non existent symbol");
1077         AddAttribute(XML_NAMESPACE_MATH, XML_OPEN,nArse);
1078         nArse[0] = static_cast<
1079             const SmMathSymbolNode* >(pRight)->GetText().GetChar(0);
1080         DBG_ASSERT(nArse[0] != 0xffff,"Non existent symbol");
1081         AddAttribute(XML_NAMESPACE_MATH, XML_CLOSE,nArse);
1082         pFences = new SvXMLElementExport(*this, XML_NAMESPACE_MATH, XML_MFENCED,
1083             sal_True,sal_True);
1084     }
1085     else if (pLeft && (pLeft->GetToken().eType != TNONE))
1086     {
1087         pRow = new SvXMLElementExport(*this, XML_NAMESPACE_MATH, XML_MROW,
1088             sal_True, sal_True);
1089         if (pNode->GetScaleMode() == SCALE_HEIGHT)
1090             AddAttribute(XML_NAMESPACE_MATH, XML_STRETCHY, XML_TRUE);
1091         else
1092             AddAttribute(XML_NAMESPACE_MATH, XML_STRETCHY, XML_FALSE);
1093         ExportNodes(pLeft, nLevel+1);
1094     }
1095     else
1096         pRow = new SvXMLElementExport(*this, XML_NAMESPACE_MATH, XML_MROW,
1097             sal_True, sal_True);
1098 
1099     if (NULL != (pTemp = pNode->GetSubNode(1)))
1100         ExportNodes(pTemp, nLevel+1);
1101     if (pFences)
1102         delete pFences;
1103     else if (pRight && (pRight->GetToken().eType != TNONE))
1104     {
1105         if (pNode->GetScaleMode() == SCALE_HEIGHT)
1106             AddAttribute(XML_NAMESPACE_MATH, XML_STRETCHY, XML_TRUE);
1107         else
1108             AddAttribute(XML_NAMESPACE_MATH, XML_STRETCHY, XML_FALSE);
1109         ExportNodes(pRight, nLevel+1);
1110     }
1111     delete pRow;
1112 }
1113 
1114 void SmXMLExport::ExportRoot(const SmNode *pNode, int nLevel)
1115 {
1116     if (pNode->GetSubNode(0))
1117     {
1118         SvXMLElementExport aRoot(*this, XML_NAMESPACE_MATH, XML_MROOT,sal_True,
1119             sal_True);
1120         ExportNodes(pNode->GetSubNode(2), nLevel+1);
1121         ExportNodes(pNode->GetSubNode(0), nLevel+1);
1122     }
1123     else
1124     {
1125         SvXMLElementExport aSqrt(*this, XML_NAMESPACE_MATH, XML_MSQRT,sal_True,
1126             sal_True);
1127         ExportNodes(pNode->GetSubNode(2), nLevel+1);
1128     }
1129 }
1130 
1131 void SmXMLExport::ExportOperator(const SmNode *pNode, int nLevel)
1132 {
1133     /*we need to either use content or font and size attributes
1134      *here*/
1135 #if 0
1136     {
1137     SvXMLElementExport aMath(*this, XML_NAMESPACE_MATH, XML_MO,
1138         sal_True,sal_False);
1139     SmTextNode *pTemp = (SmTextNode *)pNode->GetSubNode(0);
1140     GetDocHandler()->characters(pTemp->GetText());
1141     }
1142 #endif
1143     SvXMLElementExport aRow(*this, XML_NAMESPACE_MATH, XML_MROW,
1144         sal_True, sal_True);
1145     ExportNodes(pNode->GetSubNode(0), nLevel+1);
1146     ExportNodes(pNode->GetSubNode(1), nLevel+1);
1147 }
1148 
1149 void SmXMLExport::ExportAttributes(const SmNode *pNode, int nLevel)
1150 {
1151     SvXMLElementExport *pElement=0;
1152 
1153     if (pNode->GetToken().eType == TUNDERLINE)
1154     {
1155         AddAttribute(XML_NAMESPACE_MATH, XML_ACCENTUNDER,
1156             XML_TRUE);
1157         pElement = new SvXMLElementExport(*this, XML_NAMESPACE_MATH, XML_MUNDER,
1158             sal_True,sal_True);
1159     }
1160     else if (pNode->GetToken().eType != TOVERSTRIKE)
1161     {
1162         AddAttribute(XML_NAMESPACE_MATH, XML_ACCENT,
1163             XML_TRUE);
1164         pElement = new SvXMLElementExport(*this, XML_NAMESPACE_MATH, XML_MOVER,
1165             sal_True,sal_True);
1166     }
1167 
1168     ExportNodes(pNode->GetSubNode(1), nLevel+1);
1169     switch (pNode->GetToken().eType)
1170     {
1171         case TOVERLINE:
1172             {
1173             //proper entity support required
1174             SvXMLElementExport aMath(*this, XML_NAMESPACE_MATH, XML_MO,
1175                 sal_True,sal_True);
1176 #if 0
1177             GetDocHandler()->characters(
1178                 OUString(RTL_CONSTASCII_USTRINGPARAM("&overbar;")));
1179 #else
1180             sal_Unicode nArse[2] = {0xAF,0x00};
1181 #endif
1182             GetDocHandler()->characters(nArse);
1183             }
1184             break;
1185         case TUNDERLINE:
1186             {
1187             //proper entity support required
1188             SvXMLElementExport aMath(*this, XML_NAMESPACE_MATH, XML_MO,
1189                 sal_True,sal_True);
1190 #if 0
1191             GetDocHandler()->characters(
1192                 OUString(RTL_CONSTASCII_USTRINGPARAM("&underbar;")));
1193 #else
1194             sal_Unicode nArse[2] = {0x0332,0x00};
1195 #endif
1196             GetDocHandler()->characters(nArse);
1197             }
1198             break;
1199         case TOVERSTRIKE:
1200             break;
1201         default:
1202             ExportNodes(pNode->GetSubNode(0), nLevel+1);
1203             break;
1204     }
1205     delete pElement;
1206 }
1207 
1208 static bool lcl_HasEffectOnMathvariant( const SmTokenType eType )
1209 {
1210     return  eType == TBOLD || eType == TNBOLD ||
1211             eType == TITALIC || eType == TNBOLD ||
1212             eType == TSANS || eType == TSERIF || eType == TFIXED;
1213 }
1214 
1215 void SmXMLExport::ExportFont(const SmNode *pNode, int nLevel)
1216 {
1217     SvXMLElementExport *pElement = 0;
1218 
1219     //
1220     // gather the mathvariant attribut relevant data from all
1221     // successively following SmFontNodes...
1222     //
1223     int nBold   = -1;   // for the following variables: -1 = yet undefined; 0 = false; 1 = true;
1224     int nItalic = -1;   // for the following variables: -1 = yet undefined; 0 = false; 1 = true;
1225     int nSansSerifFixed   = -1;
1226     SmTokenType eNodeType = TUNKNOWN;
1227     while (lcl_HasEffectOnMathvariant( (eNodeType = pNode->GetToken().eType) ))
1228     {
1229         switch (eNodeType)
1230         {
1231             case TBOLD      : nBold   = 1; break;
1232             case TNBOLD     : nBold   = 0; break;
1233             case TITALIC    : nItalic = 1; break;
1234             case TNITALIC   : nItalic = 0; break;
1235             case TSANS      : nSansSerifFixed  = 0; break;
1236             case TSERIF     : nSansSerifFixed  = 1; break;
1237             case TFIXED     : nSansSerifFixed  = 2; break;
1238             default:
1239                 DBG_ASSERT( 0, "unexpected case" );
1240         }
1241         // According to the parser every node that is to be evaluated heres
1242         // has a single non-zero subnode at index 1!! Thus we only need to check
1243         // that single node for follow-up nodes that have an effect on the attribute.
1244         if (pNode->GetNumSubNodes() > 1 && pNode->GetSubNode(1) &&
1245             lcl_HasEffectOnMathvariant( pNode->GetSubNode(1)->GetToken().eType))
1246         {
1247             pNode = pNode->GetSubNode(1);
1248         }
1249         else
1250             break;
1251     }
1252 
1253     switch (pNode->GetToken().eType)
1254     {
1255         //wrap a phantom element around everything*/
1256         case TPHANTOM:
1257             pElement = new SvXMLElementExport(*this, XML_NAMESPACE_MATH,
1258                 XML_MPHANTOM, sal_True,sal_True);
1259             break;
1260         case TBLACK:
1261             AddAttribute(XML_NAMESPACE_MATH, XML_COLOR, XML_BLACK);
1262             break;
1263         case TWHITE:
1264             AddAttribute(XML_NAMESPACE_MATH, XML_COLOR, XML_WHITE);
1265             break;
1266         case TRED:
1267             AddAttribute(XML_NAMESPACE_MATH, XML_COLOR, XML_RED);
1268             break;
1269         case TGREEN:
1270             AddAttribute(XML_NAMESPACE_MATH, XML_COLOR, XML_GREEN);
1271             break;
1272         case TBLUE:
1273             AddAttribute(XML_NAMESPACE_MATH, XML_COLOR, XML_BLUE);
1274             break;
1275         case TCYAN:
1276             AddAttribute(XML_NAMESPACE_MATH, XML_COLOR, XML_AQUA);
1277             break;
1278         case TMAGENTA:
1279             AddAttribute(XML_NAMESPACE_MATH, XML_COLOR, XML_FUCHSIA);
1280             break;
1281         case TYELLOW:
1282             AddAttribute(XML_NAMESPACE_MATH, XML_COLOR, XML_YELLOW);
1283             break;
1284         case TSILVER:
1285             AddAttribute(XML_NAMESPACE_MATH, XML_COLOR, XML_SILVER);
1286             break;
1287         case TGRAY:
1288             AddAttribute(XML_NAMESPACE_MATH, XML_COLOR, XML_GRAY);
1289             break;
1290         case TMAROON:
1291             AddAttribute(XML_NAMESPACE_MATH, XML_COLOR, XML_MAROON);
1292             break;
1293         case TOLIVE:
1294             AddAttribute(XML_NAMESPACE_MATH, XML_COLOR, XML_OLIVE);
1295             break;
1296         case TLIME:
1297             AddAttribute(XML_NAMESPACE_MATH, XML_COLOR, XML_LIME);
1298             break;
1299         case TAQUA:
1300             AddAttribute(XML_NAMESPACE_MATH, XML_COLOR, XML_AQUA);
1301             break;
1302         case TTEAL:
1303             AddAttribute(XML_NAMESPACE_MATH, XML_COLOR, XML_TEAL);
1304             break;
1305         case TNAVY:
1306             AddAttribute(XML_NAMESPACE_MATH, XML_COLOR, XML_NAVY);
1307             break;
1308         case TFUCHSIA:
1309             AddAttribute(XML_NAMESPACE_MATH, XML_COLOR, XML_FUCHSIA);
1310             break;
1311         case TPURPLE:
1312             AddAttribute(XML_NAMESPACE_MATH, XML_COLOR, XML_PURPLE);
1313             break;
1314         case TSIZE:
1315             {
1316                 const SmFontNode *pFontNode = static_cast<const SmFontNode *>(pNode);
1317                 const Fraction &aFrac = pFontNode->GetSizeParameter();
1318 
1319                 OUStringBuffer sStrBuf;
1320                 switch(pFontNode->GetSizeType())
1321                 {
1322                     case FNTSIZ_MULTIPLY:
1323                         SvXMLUnitConverter::convertDouble(sStrBuf,
1324                             static_cast<double>(aFrac*Fraction(100.00)));
1325                         sStrBuf.append(static_cast<sal_Unicode>('%'));
1326                         break;
1327                     case FNTSIZ_DIVIDE:
1328                         SvXMLUnitConverter::convertDouble(sStrBuf,
1329                             static_cast<double>(Fraction(100.00)/aFrac));
1330                         sStrBuf.append(static_cast<sal_Unicode>('%'));
1331                         break;
1332                     case FNTSIZ_ABSOLUT:
1333                         SvXMLUnitConverter::convertDouble(sStrBuf,
1334                             static_cast<double>(aFrac));
1335                         sStrBuf.append(
1336                             GetXMLToken(XML_UNIT_PT));
1337                         break;
1338                     default:
1339                         {
1340                             //The problem here is that the wheels fall off because
1341                             //font size is stored in 100th's of a mm not pts, and
1342                             //rounding errors take their toll on the original
1343                             //value specified in points.
1344 
1345                             //Must fix StarMath to retain the original pt values
1346                             Fraction aTemp = Sm100th_mmToPts(pFontNode->GetFont().
1347                                 GetSize().Height());
1348 
1349                             if (pFontNode->GetSizeType() == FNTSIZ_MINUS)
1350                                 aTemp-=aFrac;
1351                             else
1352                                 aTemp+=aFrac;
1353 
1354                             double mytest = static_cast<double>(aTemp);
1355 
1356                             mytest = ::rtl::math::round(mytest,1);
1357                             SvXMLUnitConverter::convertDouble(sStrBuf,mytest);
1358                             sStrBuf.append(GetXMLToken(XML_UNIT_PT));
1359                         }
1360                         break;
1361                 }
1362 
1363                 OUString sStr(sStrBuf.makeStringAndClear());
1364                 AddAttribute(XML_NAMESPACE_MATH, XML_MATHSIZE, sStr);
1365             }
1366             break;
1367         case TBOLD:
1368         case TITALIC:
1369         case TNBOLD:
1370         case TNITALIC:
1371         case TFIXED:
1372         case TSANS:
1373         case TSERIF:
1374             {
1375                 // nBold:   -1 = yet undefined; 0 = false; 1 = true;
1376                 // nItalic: -1 = yet undefined; 0 = false; 1 = true;
1377                 // nSansSerifFixed: -1 = undefined; 0 = sans; 1 = serif; 2 = fixed;
1378                 const sal_Char *pText = "normal";
1379                 if (nSansSerifFixed == -1 || nSansSerifFixed == 1)
1380                 {
1381                     pText = "normal";
1382                     if (nBold == 1 && nItalic != 1)
1383                         pText = "bold";
1384                     else if (nBold != 1 && nItalic == 1)
1385                         pText = "italic";
1386                     else if (nBold == 1 && nItalic == 1)
1387                         pText = "bold-italic";
1388                 }
1389                 else if (nSansSerifFixed == 0)
1390                 {
1391                     pText = "sans-serif";
1392                     if (nBold == 1 && nItalic != 1)
1393                         pText = "bold-sans-serif";
1394                     else if (nBold != 1 && nItalic == 1)
1395                         pText = "sans-serif-italic";
1396                     else if (nBold == 1 && nItalic == 1)
1397                         pText = "sans-serif-bold-italic";
1398                 }
1399                 else if (nSansSerifFixed == 2)
1400                     pText = "monospace";    // no modifiers allowed for monospace ...
1401                 else
1402                 {
1403                     DBG_ASSERT( 0, "unexpected case" );
1404                 }
1405                 AddAttribute(XML_NAMESPACE_MATH, XML_MATHVARIANT, A2OU(pText));
1406             }
1407             break;
1408         default:
1409             break;
1410 
1411     }
1412 #if 0
1413     if (pNode->GetNumSubNodes() > 1) //or in the future is a node that
1414                                      //cannot take the currently supported
1415                                      //properties
1416 #endif
1417     //for now we will just always export with a style and not worry about
1418     //anyone else for the moment.
1419     {
1420         //wrap a style around it
1421         SvXMLElementExport aStyle(*this, XML_NAMESPACE_MATH, XML_MSTYLE, sal_True,sal_True);
1422         ExportExpression(pNode, nLevel);
1423     }
1424 #if 0
1425     else
1426         ExportNodes(pNode->GetSubNode(0), nLevel+1);
1427 #endif
1428 
1429     delete pElement;
1430 }
1431 
1432 
1433 void SmXMLExport::ExportVerticalBrace(const SmNode *pNode, int nLevel)
1434 {
1435     //Place the overbrace value OVER a vertical brace and then place that
1436     //expression OVER the overbrace value, If someone can find a
1437     //dedicated term in MathML to handle this overbrace/underbrace concept
1438     //let me know. C.
1439     XMLTokenEnum which;
1440 
1441     switch (pNode->GetToken().eType)
1442     {
1443         case TOVERBRACE:
1444         default:
1445             which = XML_MOVER;
1446             break;
1447         case TUNDERBRACE:
1448             which = XML_MUNDER;
1449             break;
1450     }
1451 
1452     DBG_ASSERT(pNode->GetNumSubNodes()==3,"Bad Vertical Brace");
1453     SvXMLElementExport aOver1(*this, XML_NAMESPACE_MATH,which, sal_True, sal_True);
1454     {//Scoping
1455         // using accents will draw the over-/underbraces too close to the base
1456         // see http://www.w3.org/TR/MathML2/chapter3.html#id.3.4.5.2
1457         // also XML_ACCENT is illegal with XML_MUNDER. Thus no XML_ACCENT attribut here!
1458 //        AddAttribute(XML_NAMESPACE_MATH, XML_ACCENT, XML_sal_True);
1459         SvXMLElementExport aOver2(*this, XML_NAMESPACE_MATH,which, sal_True, sal_True);
1460         ExportNodes(pNode->GetSubNode(0), nLevel);
1461         ExportNodes(pNode->GetSubNode(1), nLevel);
1462     }
1463     ExportNodes(pNode->GetSubNode(2), nLevel);
1464 }
1465 
1466 void SmXMLExport::ExportMatrix(const SmNode *pNode, int nLevel)
1467 {
1468     SvXMLElementExport aTable(*this, XML_NAMESPACE_MATH, XML_MTABLE, sal_True, sal_True);
1469     const SmMatrixNode *pMatrix = static_cast<const SmMatrixNode *>(pNode);
1470     sal_uInt16 i=0;
1471     for (sal_uLong y = 0; y < pMatrix->GetNumRows(); y++)
1472     {
1473         SvXMLElementExport aRow(*this, XML_NAMESPACE_MATH, XML_MTR, sal_True, sal_True);
1474         for (sal_uLong x = 0; x < pMatrix->GetNumCols(); x++)
1475             if (const SmNode *pTemp = pNode->GetSubNode(i++))
1476             {
1477                 SvXMLElementExport aCell(*this, XML_NAMESPACE_MATH, XML_MTD, sal_True, sal_True);
1478                 ExportNodes(pTemp, nLevel+1);
1479             }
1480     }
1481 }
1482 
1483 void SmXMLExport::ExportNodes(const SmNode *pNode, int nLevel)
1484 {
1485     if (!pNode)
1486         return;
1487     switch(pNode->GetType())
1488     {
1489         case NTABLE:
1490             ExportTable(pNode, nLevel);
1491             break;
1492         case NALIGN:
1493         case NBRACEBODY:
1494         case NEXPRESSION:
1495             ExportExpression(pNode, nLevel);
1496             break;
1497         case NLINE:
1498             ExportLine(pNode, nLevel);
1499             break;
1500         case NTEXT:
1501             ExportText(pNode, nLevel);
1502             break;
1503         case NSPECIAL: //NSPECIAL requires some sort of Entity preservation in the XML engine.
1504         case NGLYPH_SPECIAL:
1505         case NMATH:
1506             {
1507                 sal_Unicode cTmp = 0;
1508                 const SmTextNode *pTemp = static_cast< const SmTextNode * >(pNode);
1509                 if (pTemp->GetText().Len() > 0)
1510                     cTmp = ConvertMathToMathML( pTemp->GetText().GetChar(0) );
1511                 if (cTmp == 0)
1512                 {
1513                     // no conversion to MathML implemented -> export it as text
1514                     // thus at least it will not vanish into nothing
1515                     ExportText(pNode, nLevel);
1516                 }
1517                 else
1518                 {
1519                     //To fully handle generic MathML we need to implement the full
1520                     //operator dictionary, we will generate MathML with explicit
1521                     //stretchiness for now.
1522                     sal_Int16 nLength = GetAttrList().getLength();
1523                     sal_Bool bAddStretch=sal_True;
1524                     for ( sal_Int16 i = 0; i < nLength; i++ )
1525                     {
1526                         OUString sLocalName;
1527                         sal_uInt16 nPrefix = GetNamespaceMap().GetKeyByAttrName(
1528                             GetAttrList().getNameByIndex(i), &sLocalName );
1529 
1530                         if ( ( XML_NAMESPACE_MATH == nPrefix ) &&
1531                             IsXMLToken(sLocalName, XML_STRETCHY) )
1532                         {
1533                             bAddStretch = sal_False;
1534                             break;
1535                         }
1536                     }
1537                     if (bAddStretch)
1538                     {
1539                         AddAttribute(XML_NAMESPACE_MATH, XML_STRETCHY, XML_FALSE);
1540                     }
1541                     ExportMath(pNode, nLevel);
1542                 }
1543             }
1544             break;
1545         case NPLACE:
1546             ExportMath(pNode, nLevel);
1547             break;
1548         case NBINHOR:
1549             ExportBinaryHorizontal(pNode, nLevel);
1550             break;
1551         case NUNHOR:
1552             ExportUnaryHorizontal(pNode, nLevel);
1553             break;
1554         case NBRACE:
1555             ExportBrace(pNode, nLevel);
1556             break;
1557         case NBINVER:
1558             ExportBinaryVertical(pNode, nLevel);
1559             break;
1560         case NSUBSUP:
1561             ExportSubSupScript(pNode, nLevel);
1562             break;
1563         case NROOT:
1564             ExportRoot(pNode, nLevel);
1565             break;
1566         case NOPER:
1567             ExportOperator(pNode, nLevel);
1568             break;
1569         case NATTRIBUT:
1570             ExportAttributes(pNode, nLevel);
1571             break;
1572         case NFONT:
1573             ExportFont(pNode, nLevel);
1574             break;
1575         case NVERTICAL_BRACE:
1576             ExportVerticalBrace(pNode, nLevel);
1577             break;
1578         case NMATRIX:
1579             ExportMatrix(pNode, nLevel);
1580             break;
1581         case NBLANK:
1582             ExportBlank(pNode, nLevel);
1583             break;
1584        default:
1585             DBG_ASSERT( 0, "Warning: failed to export a node?" );
1586             break;
1587 
1588 #if 0
1589         default:
1590             {
1591             sal_uLong  nSize = pNode->GetNumSubNodes();
1592             for (sal_uLong i = 0; i < nSize; i++)
1593                 if (SmNode *pTemp = pNode->GetSubNode(i))
1594                     ExportNodes(pTemp, nLevel+1);
1595             }
1596             break;
1597 #endif
1598     }
1599 }
1600 
1601 ////////////////////////////////////////////////////////////
1602 
1603