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 allthough 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 existant 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 existant 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 existant 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 TSIZE:
1285             {
1286                 const SmFontNode *pFontNode = static_cast<const SmFontNode *>(pNode);
1287                 const Fraction &aFrac = pFontNode->GetSizeParameter();
1288 
1289                 OUStringBuffer sStrBuf;
1290                 switch(pFontNode->GetSizeType())
1291                 {
1292                     case FNTSIZ_MULTIPLY:
1293                         SvXMLUnitConverter::convertDouble(sStrBuf,
1294                             static_cast<double>(aFrac*Fraction(100.00)));
1295                         sStrBuf.append(static_cast<sal_Unicode>('%'));
1296                         break;
1297                     case FNTSIZ_DIVIDE:
1298                         SvXMLUnitConverter::convertDouble(sStrBuf,
1299                             static_cast<double>(Fraction(100.00)/aFrac));
1300                         sStrBuf.append(static_cast<sal_Unicode>('%'));
1301                         break;
1302                     case FNTSIZ_ABSOLUT:
1303                         SvXMLUnitConverter::convertDouble(sStrBuf,
1304                             static_cast<double>(aFrac));
1305                         sStrBuf.append(
1306                             GetXMLToken(XML_UNIT_PT));
1307                         break;
1308                     default:
1309                         {
1310                             //The problem here is that the wheels fall off because
1311                             //font size is stored in 100th's of a mm not pts, and
1312                             //rounding errors take their toll on the original
1313                             //value specified in points.
1314 
1315                             //Must fix StarMath to retain the original pt values
1316                             Fraction aTemp = Sm100th_mmToPts(pFontNode->GetFont().
1317                                 GetSize().Height());
1318 
1319                             if (pFontNode->GetSizeType() == FNTSIZ_MINUS)
1320                                 aTemp-=aFrac;
1321                             else
1322                                 aTemp+=aFrac;
1323 
1324                             double mytest = static_cast<double>(aTemp);
1325 
1326                             mytest = ::rtl::math::round(mytest,1);
1327                             SvXMLUnitConverter::convertDouble(sStrBuf,mytest);
1328                             sStrBuf.append(GetXMLToken(XML_UNIT_PT));
1329                         }
1330                         break;
1331                 }
1332 
1333                 OUString sStr(sStrBuf.makeStringAndClear());
1334                 AddAttribute(XML_NAMESPACE_MATH, XML_MATHSIZE, sStr);
1335             }
1336             break;
1337         case TBOLD:
1338         case TITALIC:
1339         case TNBOLD:
1340         case TNITALIC:
1341         case TFIXED:
1342         case TSANS:
1343         case TSERIF:
1344             {
1345                 // nBold:   -1 = yet undefined; 0 = false; 1 = true;
1346                 // nItalic: -1 = yet undefined; 0 = false; 1 = true;
1347                 // nSansSerifFixed: -1 = undefined; 0 = sans; 1 = serif; 2 = fixed;
1348                 const sal_Char *pText = "normal";
1349                 if (nSansSerifFixed == -1 || nSansSerifFixed == 1)
1350                 {
1351                     pText = "normal";
1352                     if (nBold == 1 && nItalic != 1)
1353                         pText = "bold";
1354                     else if (nBold != 1 && nItalic == 1)
1355                         pText = "italic";
1356                     else if (nBold == 1 && nItalic == 1)
1357                         pText = "bold-italic";
1358                 }
1359                 else if (nSansSerifFixed == 0)
1360                 {
1361                     pText = "sans-serif";
1362                     if (nBold == 1 && nItalic != 1)
1363                         pText = "bold-sans-serif";
1364                     else if (nBold != 1 && nItalic == 1)
1365                         pText = "sans-serif-italic";
1366                     else if (nBold == 1 && nItalic == 1)
1367                         pText = "sans-serif-bold-italic";
1368                 }
1369                 else if (nSansSerifFixed == 2)
1370                     pText = "monospace";    // no modifiers allowed for monospace ...
1371                 else
1372                 {
1373                     DBG_ASSERT( 0, "unexpected case" );
1374                 }
1375                 AddAttribute(XML_NAMESPACE_MATH, XML_MATHVARIANT, A2OU(pText));
1376             }
1377             break;
1378         default:
1379             break;
1380 
1381     }
1382 #if 0
1383     if (pNode->GetNumSubNodes() > 1) //or in the future is a node that
1384                                      //cannot take the currently supported
1385                                      //properties
1386 #endif
1387     //for now we will just always export with a style and not worry about
1388     //anyone else for the moment.
1389     {
1390         //wrap a style around it
1391         SvXMLElementExport aStyle(*this, XML_NAMESPACE_MATH, XML_MSTYLE, sal_True,sal_True);
1392         ExportExpression(pNode, nLevel);
1393     }
1394 #if 0
1395     else
1396         ExportNodes(pNode->GetSubNode(0), nLevel+1);
1397 #endif
1398 
1399     delete pElement;
1400 }
1401 
1402 
1403 void SmXMLExport::ExportVerticalBrace(const SmNode *pNode, int nLevel)
1404 {
1405     //Place the overbrace value OVER a vertical brace and then place that
1406     //expression OVER the overbrace value, If someone can find a
1407     //dedicated term in MathML to handle this overbrace/underbrace concept
1408     //let me know. C.
1409     XMLTokenEnum which;
1410 
1411     switch (pNode->GetToken().eType)
1412     {
1413         case TOVERBRACE:
1414         default:
1415             which = XML_MOVER;
1416             break;
1417         case TUNDERBRACE:
1418             which = XML_MUNDER;
1419             break;
1420     }
1421 
1422     DBG_ASSERT(pNode->GetNumSubNodes()==3,"Bad Vertical Brace");
1423     SvXMLElementExport aOver1(*this, XML_NAMESPACE_MATH,which, sal_True, sal_True);
1424     {//Scoping
1425         // using accents will draw the over-/underbraces too close to the base
1426         // see http://www.w3.org/TR/MathML2/chapter3.html#id.3.4.5.2
1427         // also XML_ACCENT is illegal with XML_MUNDER. Thus no XML_ACCENT attribut here!
1428 //        AddAttribute(XML_NAMESPACE_MATH, XML_ACCENT, XML_sal_True);
1429         SvXMLElementExport aOver2(*this, XML_NAMESPACE_MATH,which, sal_True, sal_True);
1430         ExportNodes(pNode->GetSubNode(0), nLevel);
1431         ExportNodes(pNode->GetSubNode(1), nLevel);
1432     }
1433     ExportNodes(pNode->GetSubNode(2), nLevel);
1434 }
1435 
1436 void SmXMLExport::ExportMatrix(const SmNode *pNode, int nLevel)
1437 {
1438     SvXMLElementExport aTable(*this, XML_NAMESPACE_MATH, XML_MTABLE, sal_True, sal_True);
1439     const SmMatrixNode *pMatrix = static_cast<const SmMatrixNode *>(pNode);
1440     sal_uInt16 i=0;
1441     for (sal_uLong y = 0; y < pMatrix->GetNumRows(); y++)
1442     {
1443         SvXMLElementExport aRow(*this, XML_NAMESPACE_MATH, XML_MTR, sal_True, sal_True);
1444         for (sal_uLong x = 0; x < pMatrix->GetNumCols(); x++)
1445             if (const SmNode *pTemp = pNode->GetSubNode(i++))
1446             {
1447                 SvXMLElementExport aCell(*this, XML_NAMESPACE_MATH, XML_MTD, sal_True, sal_True);
1448                 ExportNodes(pTemp, nLevel+1);
1449             }
1450     }
1451 }
1452 
1453 void SmXMLExport::ExportNodes(const SmNode *pNode, int nLevel)
1454 {
1455     if (!pNode)
1456         return;
1457     switch(pNode->GetType())
1458     {
1459         case NTABLE:
1460             ExportTable(pNode, nLevel);
1461             break;
1462         case NALIGN:
1463         case NBRACEBODY:
1464         case NEXPRESSION:
1465             ExportExpression(pNode, nLevel);
1466             break;
1467         case NLINE:
1468             ExportLine(pNode, nLevel);
1469             break;
1470         case NTEXT:
1471             ExportText(pNode, nLevel);
1472             break;
1473         case NSPECIAL: //NSPECIAL requires some sort of Entity preservation in the XML engine.
1474         case NGLYPH_SPECIAL:
1475         case NMATH:
1476             {
1477                 sal_Unicode cTmp = 0;
1478                 const SmTextNode *pTemp = static_cast< const SmTextNode * >(pNode);
1479                 if (pTemp->GetText().Len() > 0)
1480                     cTmp = ConvertMathToMathML( pTemp->GetText().GetChar(0) );
1481                 if (cTmp == 0)
1482                 {
1483                     // no conversion to MathML implemented -> export it as text
1484                     // thus at least it will not vanish into nothing
1485                     ExportText(pNode, nLevel);
1486                 }
1487                 else
1488                 {
1489                     //To fully handle generic MathML we need to implement the full
1490                     //operator dictionary, we will generate MathML with explicit
1491                     //stretchiness for now.
1492                     sal_Int16 nLength = GetAttrList().getLength();
1493                     sal_Bool bAddStretch=sal_True;
1494                     for ( sal_Int16 i = 0; i < nLength; i++ )
1495                     {
1496                         OUString sLocalName;
1497                         sal_uInt16 nPrefix = GetNamespaceMap().GetKeyByAttrName(
1498                             GetAttrList().getNameByIndex(i), &sLocalName );
1499 
1500                         if ( ( XML_NAMESPACE_MATH == nPrefix ) &&
1501                             IsXMLToken(sLocalName, XML_STRETCHY) )
1502                         {
1503                             bAddStretch = sal_False;
1504                             break;
1505                         }
1506                     }
1507                     if (bAddStretch)
1508                     {
1509                         AddAttribute(XML_NAMESPACE_MATH, XML_STRETCHY, XML_FALSE);
1510                     }
1511                     ExportMath(pNode, nLevel);
1512                 }
1513             }
1514             break;
1515         case NPLACE:
1516             ExportMath(pNode, nLevel);
1517             break;
1518         case NBINHOR:
1519             ExportBinaryHorizontal(pNode, nLevel);
1520             break;
1521         case NUNHOR:
1522             ExportUnaryHorizontal(pNode, nLevel);
1523             break;
1524         case NBRACE:
1525             ExportBrace(pNode, nLevel);
1526             break;
1527         case NBINVER:
1528             ExportBinaryVertical(pNode, nLevel);
1529             break;
1530         case NSUBSUP:
1531             ExportSubSupScript(pNode, nLevel);
1532             break;
1533         case NROOT:
1534             ExportRoot(pNode, nLevel);
1535             break;
1536         case NOPER:
1537             ExportOperator(pNode, nLevel);
1538             break;
1539         case NATTRIBUT:
1540             ExportAttributes(pNode, nLevel);
1541             break;
1542         case NFONT:
1543             ExportFont(pNode, nLevel);
1544             break;
1545         case NVERTICAL_BRACE:
1546             ExportVerticalBrace(pNode, nLevel);
1547             break;
1548         case NMATRIX:
1549             ExportMatrix(pNode, nLevel);
1550             break;
1551         case NBLANK:
1552             ExportBlank(pNode, nLevel);
1553             break;
1554        default:
1555             DBG_ASSERT( 0, "Warning: failed to export a node?" );
1556             break;
1557 
1558 #if 0
1559         default:
1560             {
1561             sal_uLong  nSize = pNode->GetNumSubNodes();
1562             for (sal_uLong i = 0; i < nSize; i++)
1563                 if (SmNode *pTemp = pNode->GetSubNode(i))
1564                     ExportNodes(pTemp, nLevel+1);
1565             }
1566             break;
1567 #endif
1568     }
1569 }
1570 
1571 ////////////////////////////////////////////////////////////
1572 
1573