1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  *   Licensed to the Apache Software Foundation (ASF) under one or more
12  *   contributor license agreements. See the NOTICE file distributed
13  *   with this work for additional information regarding copyright
14  *   ownership. The ASF licenses this file to you under the Apache
15  *   License, Version 2.0 (the "License"); you may not use this file
16  *   except in compliance with the License. You may obtain a copy of
17  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 #include "mathtype.hxx"
21 
22 #include <filter/msfilter/classids.hxx>
23 #include <osl/diagnose.h>
24 #include <sfx2/docfile.hxx>
25 #include <sot/storage.hxx>
26 #include <sal/log.hxx>
27 
28 #include "eqnolefilehdr.hxx"
29 #include <node.hxx>
30 
Init()31 void MathType::Init()
32 {
33     //These are the default MathType sizes
34     aSizeTable.push_back(12);
35     aSizeTable.push_back(8);
36     aSizeTable.push_back(6);
37     aSizeTable.push_back(24);
38     aSizeTable.push_back(10);
39     aSizeTable.push_back(12);
40     aSizeTable.push_back(12);
41 
42     /*
43     These are the default MathType italic/bold settings If mathtype is changed
44     from its defaults, there is nothing we can do, as this information is not
45     stored in the document
46     */
47     MathTypeFont aFont;
48     for(sal_uInt8 i=1;i<=11;i++)
49     {
50         aFont.nTface = i+128;
51         switch (i)
52         {
53             default:
54                 aFont.nStyle=0;
55                 break;
56             case 3:
57             case 4:
58                 aFont.nStyle=1;
59                 break;
60             case 7:
61                 aFont.nStyle=2;
62                 break;
63         }
64         aUserStyles.insert(aFont);
65     }
66 }
67 
68 
69 /*ToDo replace with table rather than switch, returns
70  sal_True in the case that the char is just a char, and
71  sal_False if the character is an operator which must not be
72  placed inside the quote sequence designed to protect
73  against being parsed as a keyword
74 
75  General solution required to force starmath to handle
76  unicode math chars the way it handles its own math
77  chars rather than handle them as text as it will do
78  for the default case below, i.e. incorrect spacing
79  between math symbols and ordinary text e.g. 1=2 rather
80  than 1 = 2
81  */
LookupChar(sal_Unicode nChar,OUStringBuffer & rRet,sal_uInt8 nVersion,sal_uInt8 nTypeFace)82 bool MathType::LookupChar(sal_Unicode nChar,OUStringBuffer &rRet,sal_uInt8 nVersion,
83     sal_uInt8 nTypeFace)
84 {
85     bool bRet=false;
86     const char *pC = nullptr;
87     switch(nChar)
88     {
89         case 0x0000:
90             pC = " none ";
91             break;
92         case 0x00ac:
93             pC = " neg ";
94             break;
95         case 0x00b1:
96             pC = " +- ";
97             break;
98         case '(':
99             pC = " \\( ";
100             break;
101         case ')':
102             pC = " \\) ";
103             break;
104         case '[':
105             pC = " \\[ ";
106             break;
107         case ']':
108             pC = " \\] ";
109             break;
110         case '.':
111             pC = " \".\" ";
112             break;
113         case 0xae:
114             if ((nVersion < 3) && (nTypeFace == 0x86))
115                 pC = " rightarrow ";
116             else
117             {
118                 rRet.append(OUStringChar(nChar));
119                 bRet=true;
120             }
121             break;
122         case 0x00fb:
123             if ((nVersion < 3) && (nTypeFace == 0x81))
124                 nChar = 0xDF;
125             rRet.append(OUStringChar(nChar));
126             bRet=true;
127             break;
128         case 'a':
129             if ((nVersion < 3) && (nTypeFace == 0x84))
130                 nChar = 0x3b1;
131             rRet.append(OUStringChar(nChar));
132             bRet=true;
133             break;
134         case 'b':
135             if ((nVersion < 3) && (nTypeFace == 0x84))
136                 nChar = 0x3b2;
137             rRet.append(OUStringChar(nChar));
138             bRet=true;
139             break;
140         case 'l':
141             if ((nVersion < 3) && (nTypeFace == 0x84))
142                 nChar = 0x3bb;
143             rRet.append(OUStringChar(nChar));
144             bRet=true;
145             break;
146         case 'n':
147             if ((nVersion < 3) && (nTypeFace == 0x84))
148                 nChar = 0x3bd;
149             rRet.append(OUStringChar(nChar));
150             bRet=true;
151             break;
152         case 'r':
153             if ((nVersion < 3) && (nTypeFace == 0x84))
154                 nChar = 0x3c1;
155             rRet.append(OUStringChar(nChar));
156             bRet=true;
157             break;
158         case 'D':
159             if ((nVersion < 3) && (nTypeFace == 0x84))
160                 nChar = 0x394;
161             rRet.append(OUStringChar(nChar));
162             bRet=true;
163             break;
164         case 0xa9:
165             if ((nVersion < 3) && (nTypeFace == 0x82))
166                 nChar = '\'';
167             rRet.append(OUStringChar(nChar));
168             bRet=true;
169             break;
170         case 0x00f1:
171             if ((nVersion < 3) && (nTypeFace == 0x86))
172                 pC = " \\rangle ";
173             else
174             {
175                 rRet.append(OUStringChar(nChar));
176                 bRet=true;
177             }
178             break;
179         case 0x00a3:
180             if ((nVersion < 3) && (nTypeFace == 0x86))
181                 pC = " <= ";
182             else
183             {
184                 rRet.append(OUStringChar(nChar));
185                 bRet=true;
186             }
187             break;
188         case 0x00de:
189             if ((nVersion < 3) && (nTypeFace == 0x86))
190                 pC = " drarrow ";
191             else
192             {
193                 rRet.append(OUStringChar(nChar));
194                 bRet=true;
195             }
196             break;
197         case 0x0057:
198             if ((nVersion < 3) && (nTypeFace == 0x85))
199                 pC = " %OMEGA ";
200             else
201             {
202                 rRet.append(OUStringChar(nChar));
203                 bRet=true;
204             }
205             break;
206         case 0x007b:
207             pC = " lbrace ";
208             break;
209         case 0x007c:
210             pC = " \\lline ";
211             break;
212         case 0x007d:
213             pC = " rbrace ";
214             break;
215         case 0x007e:
216             pC = " \"~\" ";
217             break;
218         case 0x2224:
219             pC = " ndivides ";
220             break;
221         case 0x2225:
222             pC = " parallel ";
223             break;
224         case 0x00d7:
225             if (nVersion < 3)
226                 pC = " cdot ";
227             else
228                 pC = " times ";
229             break;
230         case 0x00f7:
231             pC = " div ";
232             break;
233         case 0x019b:
234             pC = " lambdabar ";
235             break;
236         case 0x2026:
237             pC = " dotslow ";
238             break;
239         case 0x2022:
240             pC = " cdot ";
241             break;
242         case 0x2102:
243             pC = " setC ";
244             break;
245         case 0x210f:
246             pC = " hbar ";
247             break;
248         case 0x2111:
249             pC = " Im ";
250             break;
251         case 0x2115:
252             pC = " setN ";
253             break;
254         case 0x2118:
255             pC = " wp ";
256             break;
257         case 0x211a:
258             pC = " setQ ";
259             break;
260         case 0x211c:
261             pC = " Re ";
262             break;
263         case 0x211d:
264             pC = " setR ";
265             break;
266         case 0x2124:
267             pC = " setZ ";
268             break;
269         case 0x2135:
270             pC = " aleph ";
271             break;
272         case 0x2190:
273             pC = " leftarrow ";
274             break;
275         case 0x2191:
276             pC = " uparrow ";
277             break;
278         case 0x2192:
279             pC = " rightarrow ";
280             break;
281         case 0x0362:
282             pC = " widevec ";
283             break;
284         case 0x2193:
285             pC = " downarrow ";
286             break;
287         case 0x21d0:
288             pC = " dlarrow ";
289             break;
290         case 0x21d2:
291             pC = " drarrow ";
292             break;
293         case 0x21d4:
294             pC = " dlrarrow ";
295             break;
296         case 0x2200:
297             pC = " forall ";
298             break;
299         case 0x2202:
300             pC = " partial ";
301             break;
302         case 0x2203:
303             pC = " exists ";
304             break;
305         case 0x2204:
306             pC = " notexists ";
307             break;
308         case 0x2205:
309             pC = " emptyset ";
310             break;
311         case 0x2207:
312             pC = " nabla ";
313             break;
314         case 0x2208: // in
315         case 0x2209: // notin
316             rRet.append(" func ").append(OUStringChar(nChar)).append(" ");
317             break;
318         case 0x220d: // owns
319             rRet.append(u" func \u220b ");
320             break;
321         case 0x220f:
322             pC = " prod ";
323             break;
324         case 0x2210:
325             pC = " coprod ";
326             break;
327         case 0x2211:
328             pC = " sum ";
329             break;
330         case 0x2212:
331             pC = " - ";
332             break;
333         case 0x2213:
334             pC = " -+ ";
335             break;
336         case 0x2217:
337             pC = " * ";
338             break;
339         case 0x2218:
340             pC = " circ ";
341             break;
342         case 0x221d:
343             pC = " prop ";
344             break;
345         case 0x221e:
346             pC = " infinity ";
347             break;
348         case 0x2227:
349             pC = " and ";
350             break;
351         case 0x2228:
352             pC = " or ";
353             break;
354         case 0x2229:
355             pC = " intersection ";
356             break;
357         case 0x222a:
358             pC = " union ";
359             break;
360         case 0x222b:
361             pC = " int ";
362             break;
363         case 0x222c:
364             pC = " iint ";
365             break;
366         case 0x222d:
367             pC = " iiint ";
368             break;
369         case 0x222e:
370             pC = " lint ";
371             break;
372         case 0x222f:
373             pC = " llint ";
374             break;
375         case 0x2230:
376             pC = " lllint ";
377             break;
378         case 0x2245:
379             pC = " simeq ";
380             break;
381         case 0x2248:
382             pC = " approx ";
383             break;
384         case 0x2260:
385             pC = " <> ";
386             break;
387         case 0x2261:
388             pC = " equiv ";
389             break;
390         case 0x2264:
391             pC = " <= ";
392             break;
393         case 0x2265:
394             pC = " >= ";
395             break;
396 
397         case 0x227A:
398             pC = " prec ";
399             break;
400         case 0x227B:
401             pC = " succ ";
402             break;
403         case 0x227C:
404             pC = " preccurlyeq ";
405             break;
406         case 0x227D:
407             pC = " succcurlyeq ";
408             break;
409         case 0x227E:
410             pC = " precsim ";
411             break;
412         case 0x227F:
413             pC = " succsim ";
414             break;
415         case 0x2280:
416             pC = " nprec ";
417             break;
418         case 0x2281:
419             pC = " nsucc ";
420             break;
421 
422         case 0x2282: // subset
423         case 0x2283: // supset
424         case 0x2284: // nsubset
425         case 0x2285: // nsupset
426         case 0x2286: // subseteq
427         case 0x2287: // supseteq
428         case 0x2288: // nsubseteq
429         case 0x2289: // nsupseteq
430         case 0x22b2: // NORMAL SUBGROUP OF
431         case 0x22b3: // CONTAINS AS NORMAL SUBGROUP
432             rRet.append(" func ").append(OUStringChar(nChar)).append(" ");
433             break;
434         case 0x22a5:
435             pC = " ortho ";
436             break;
437         case 0x22c5:
438             pC = " cdot ";
439             break;
440         case 0x22ee:
441             pC = " dotsvert ";
442             break;
443         case 0x22ef:
444             pC = " dotsaxis ";
445             break;
446         case 0x22f0:
447             pC = " dotsup ";
448             break;
449         case 0x22f1:
450             pC = " dotsdown ";
451             break;
452         case MS_LANGLE:
453         case MS_LMATHANGLE:
454             pC = " langle ";
455             break;
456         case MS_RANGLE:
457         case MS_RMATHANGLE:
458             pC = " rangle ";
459             break;
460         case 0x301a:
461             pC = " ldbracket ";
462             break;
463         case 0x301b:
464             pC = " rdbracket ";
465             break;
466         case 0xe083:
467             rRet.append("+");
468             bRet=true;
469             break;
470         case '^':
471         case 0xe091:
472             pC = " widehat ";
473             break;
474         case 0xe096:
475             pC = " widetilde ";
476             break;
477         case 0xe098:
478             pC = " widevec ";
479             break;
480         case 0xE421:
481             pC = " geslant ";
482             break;
483         case 0xE425:
484             pC = " leslant ";
485             break;
486         case 0xeb01:    //no space
487         case 0xeb08:    //normal space
488             bRet=true;
489             break;
490         case 0xef04:    //tiny space
491         case 0xef05:    //tiny space
492         case 0xeb02:    //small space
493         case 0xeb04:    //medium space
494             rRet.append("`");
495             break;
496         case 0xeb05:    //large space
497             rRet.append("~");
498             break;
499         case 0x3a9:
500             pC = " %OMEGA ";
501             break;
502         default:
503             rRet.append(OUStringChar(nChar));
504             bRet=true;
505             break;
506     }
507     if (pC)
508         rRet.appendAscii(pC);
509     return bRet;
510 }
511 
AppendStyleToText(OUString & rRet)512 void MathTypeFont::AppendStyleToText(OUString &rRet)
513 {
514     const char *pC = nullptr;
515     switch (nStyle)
516     {
517         default:
518         case 0:
519             break;
520         case 1:
521             pC = " ital ";
522             break;
523         case 2:
524             pC = " bold ";
525             break;
526         case 3:
527             pC = " bold italic";
528             break;
529     }
530     if (pC)
531         rRet += OUString::createFromAscii( pC );
532 }
533 
TypeFaceToString(OUString & rTxt,sal_uInt8 nFace)534 void MathType::TypeFaceToString(OUString &rTxt,sal_uInt8 nFace)
535 {
536     MathTypeFont aFont(nFace);
537     MathTypeFontSet::iterator aItr = aUserStyles.find(aFont);
538     if (aItr != aUserStyles.end())
539         aFont.nStyle = aItr->nStyle;
540     aFont.AppendStyleToText(rTxt);
541 }
542 
Parse(SotStorage * pStor)543 bool MathType::Parse(SotStorage *pStor)
544 {
545     tools::SvRef<SotStorageStream> xSrc = pStor->OpenSotStream(
546         "Equation Native",
547         StreamMode::STD_READ);
548     if ( (!xSrc.is()) || (ERRCODE_NONE != xSrc->GetError()))
549         return false;
550     return Parse(xSrc.get());
551 }
552 
Parse(SvStream * pStream)553 bool MathType::Parse(SvStream* pStream)
554 {
555     pS = pStream;
556     pS->SetEndian( SvStreamEndian::LITTLE );
557 
558     EQNOLEFILEHDR aHdr;
559     aHdr.Read(pS);
560     sal_uInt8 nProdVersion;
561     sal_uInt8 nProdSubVersion;
562     sal_uInt8 nPlatform;
563     sal_uInt8 nProduct;
564     pS->ReadUChar( nVersion );
565     pS->ReadUChar( nPlatform );
566     pS->ReadUChar( nProduct );
567     pS->ReadUChar( nProdVersion );
568     pS->ReadUChar( nProdSubVersion );
569 
570     if (nVersion > 3)   // allow only supported versions of MathType to be parsed
571         return false;
572 
573     bool bRet = HandleRecords(0);
574     //little crude hack to close occasionally open expressions
575     //a sophisticated system to determine what expressions are
576     //opened is required, but this is as much work as rewriting
577     //starmaths internals.
578     rRet.append("{}");
579 
580     return bRet;
581 }
582 
lcl_PrependDummyTerm(OUStringBuffer & rRet,sal_Int32 & rTextStart)583 static void lcl_PrependDummyTerm(OUStringBuffer &rRet, sal_Int32 &rTextStart)
584 {
585     if ((rTextStart < rRet.getLength()) &&
586         (rRet[rTextStart] == '=') &&
587         ((rTextStart == 0) || (rRet[ rTextStart-1 ] == '{'))
588        )
589     {
590         rRet.insert(rTextStart, " {}");
591         rTextStart+=3;
592     }
593 }
594 
lcl_AppendDummyTerm(OUStringBuffer & rRet)595 static void lcl_AppendDummyTerm(OUStringBuffer &rRet)
596 {
597     bool bOk=false;
598     for(int nI=rRet.getLength()-1;nI >= 0; nI--)
599     {
600         sal_Int32 nIdx = sal::static_int_cast< sal_Int32 >(nI);
601         sal_Unicode nChar = rRet[nIdx];
602         if (nChar == ' ')
603             continue;
604         if (rRet[nIdx] != '{')
605             bOk=true;
606         break;
607     }
608     if (!bOk)   //No term, use dummy
609         rRet.append(" {}");
610 }
611 
HandleNudge()612 void MathType::HandleNudge()
613 {
614     sal_uInt8 nXNudge;
615     pS->ReadUChar( nXNudge );
616     sal_uInt8 nYNudge;
617     pS->ReadUChar( nYNudge );
618     if (nXNudge == 128 && nYNudge == 128)
619     {
620         sal_uInt16 nXLongNudge;
621         sal_uInt16 nYLongNudge;
622         pS->ReadUInt16( nXLongNudge );
623         pS->ReadUInt16( nYLongNudge );
624     }
625 }
626 
627 /* Fabulously complicated as many tokens have to be reordered and generally
628  * moved around from mathtypes paradigm to starmaths. */
HandleRecords(int nLevel,sal_uInt8 nSelector,sal_uInt8 nVariation,int nMatrixRows,int nMatrixCols)629 bool MathType::HandleRecords(int nLevel, sal_uInt8 nSelector,
630     sal_uInt8 nVariation, int nMatrixRows, int nMatrixCols)
631 {
632     //depth-protect
633     if (nLevel > 1024)
634         return false;
635 
636     sal_uInt8 nTag,nRecord;
637     sal_uInt8 nTabType,nTabStops;
638     sal_uInt16 nTabOffset;
639     int i, newline=0;
640     bool bSilent=false;
641     int nPart=0;
642     OUString sPush,sMainTerm;
643     int nSetSize=0,nSetAlign=0;
644     int nCurRow=0,nCurCol=0;
645     bool bOpenString=false;
646     sal_Int32 nTextStart = 0;
647     sal_Int32 nSubSupStartPos = 0;
648     sal_Int32 nLastTemplateBracket=-1;
649     bool bRet = true;
650 
651     do
652     {
653         nTag = 0;
654         pS->ReadUChar( nTag );
655         nRecord = nTag&0x0F;
656 
657         /*MathType strings can of course include words which
658          *are StarMath keywords, the simplest solution is
659          to escape strings of greater than len 1 with double
660          quotes to avoid scanning the TokenTable for matches
661 
662          Unfortunately it may turn out that the string gets
663          split during the handling of a character emblishment
664          so this special case must be handled in the
665          character handler case 2:
666          */
667         if ((nRecord == CHAR) && (!bOpenString))
668         {
669             bOpenString=true;
670             nTextStart = rRet.getLength();
671         }
672         else if ((nRecord != CHAR) && bOpenString)
673         {
674             bOpenString=false;
675             if ((rRet.getLength() - nTextStart) > 1)
676             {
677                 OUString aStr;
678                 TypeFaceToString(aStr,nTypeFace);
679                 aStr += "\"";
680                 rRet.insert(nTextStart,aStr);
681                 rRet.append("\"");
682             }
683             else if (nRecord == END && !rRet.isEmpty())
684             {
685                 sal_Unicode cChar = 0;
686                 sal_Int32 nI = rRet.getLength()-1;
687                 while (nI && ((cChar = rRet[nI]) == ' '))
688                     --nI;
689                 if ((cChar == '=') || (cChar == '+') || (cChar == '-'))
690                     rRet.append("{}");
691             }
692         }
693 
694         switch(nRecord)
695         {
696             case LINE:
697                 {
698                     if (xfLMOVE(nTag))
699                         HandleNudge();
700 
701                     if (newline>0)
702                         rRet.append("\nnewline\n");
703                     if (!(xfNULL(nTag)))
704                     {
705                         switch (nSelector)
706                         {
707                         case tmANGLE:
708                             if (nVariation==0)
709                                 rRet.append(" langle ");
710                             else if (nVariation==1)
711                                 rRet.append(" \\langle ");
712                             break;
713                         case tmPAREN:
714                             if (nVariation==0)
715                                 rRet.append(" left (");
716                             else if (nVariation==1)
717                                 rRet.append("\\(");
718                             break;
719                         case tmBRACE:
720                             if ((nVariation==0) || (nVariation==1))
721                                 rRet.append(" left lbrace ");
722                             else
723                                 rRet.append(" left none ");
724                             break;
725                         case tmBRACK:
726                             if (nVariation==0)
727                                 rRet.append(" left [");
728                             else if (nVariation==1)
729                                 rRet.append("\\[");
730                             break;
731                         case tmLBLB:
732                         case tmLBRP:
733                             rRet.append(" \\[");
734                             break;
735                         case tmBAR:
736                             if (nVariation==0)
737                                 rRet.append(" lline ");
738                             else if (nVariation==1)
739                                 rRet.append(" \\lline ");
740                             break;
741                         case tmDBAR:
742                             if (nVariation==0)
743                                 rRet.append(" ldline ");
744                             else if (nVariation==1)
745                                 rRet.append(" \\ldline ");
746                             break;
747                         case tmFLOOR:
748                             if (nVariation == 0 || nVariation & 0x01) // tvFENCE_L
749                                 rRet.append(" left lfloor ");
750                             else
751                                 rRet.append(" left none ");
752                             break;
753                         case tmCEILING:
754                             if (nVariation==0)
755                                 rRet.append(" lceil ");
756                             else if (nVariation==1)
757                                 rRet.append(" \\lceil ");
758                             break;
759                         case tmRBRB:
760                         case tmRBLB:
761                             rRet.append(" \\]");
762                             break;
763                         case tmLPRB:
764                             rRet.append(" \\(");
765                             break;
766                         case tmROOT:
767                             if (nPart == 0)
768                             {
769                                 if (nVariation == 0)
770                                     rRet.append(" sqrt");
771                                 else
772                                 {
773                                     rRet.append(" nroot");
774                                     sPush = rRet.makeStringAndClear();
775                                 }
776                             }
777                             rRet.append(" {");
778                             break;
779                         case tmFRACT:
780                             if (nPart == 0)
781                                 rRet.append(" { ");
782 
783 
784                             if (nPart == 1)
785                                 rRet.append(" over ");
786                             rRet.append(" {");
787                             break;
788                         case tmSCRIPT:
789                             nSubSupStartPos = rRet.getLength();
790                             if ((nVariation == 0) ||
791                                     ((nVariation == 2) && (nPart==1)))
792                             {
793                                 lcl_AppendDummyTerm(rRet);
794                                 rRet.append(" rSup");
795                             }
796                             else if ((nVariation == 1) ||
797                                     ((nVariation == 2) && (nPart==0)))
798                             {
799                                 lcl_AppendDummyTerm(rRet);
800                                 rRet.append(" rSub");
801                             }
802                             rRet.append(" {");
803                             break;
804                         case tmUBAR:
805                             if (nVariation == 0)
806                                 rRet.append(" {underline ");
807                             else if (nVariation == 1)
808                                 rRet.append(" {underline underline ");
809                             rRet.append(" {");
810                             break;
811                         case tmOBAR:
812                             if (nVariation == 0)
813                                 rRet.append(" {overline ");
814                             else if (nVariation == 1)
815                                 rRet.append(" {overline overline ");
816                             rRet.append(" {");
817                             break;
818                         case tmLARROW:
819                             if (nPart == 0)
820                             {
821                                 if (nVariation == 0)
822                                     rRet.append(" widevec ");//left arrow above
823                                 else if (nVariation == 1)
824                                     rRet.append(" widevec ");//left arrow below
825                                 rRet.append(" {");
826                             }
827                             break;
828                         case tmRARROW:
829                             if (nPart == 0)
830                             {
831                                 if (nVariation == 0)
832                                     rRet.append(" widevec ");//right arrow above
833                                 else if (nVariation == 1)
834                                     rRet.append(" widevec ");//right arrow below
835                                 rRet.append(" {");
836                             }
837                             break;
838                         case tmBARROW:
839                             if (nPart == 0)
840                             {
841                                 if (nVariation == 0)
842                                     rRet.append(" widevec ");//double arrow above
843                                 else if (nVariation == 1)
844                                     rRet.append(" widevec ");//double arrow below
845                                 rRet.append(" {");
846                             }
847                             break;
848                         case tmSINT:
849                             if (nPart == 0)
850                             {
851                                 if ((nVariation == 3) || (nVariation == 4))
852                                     rRet.append(" lInt");
853                                 else
854                                     rRet.append(" Int");
855                                 if ( (nVariation != 0) && (nVariation != 3))
856                                 {
857                                     sPush = rRet.makeStringAndClear();
858                                 }
859                             }
860                             if (((nVariation == 1) ||
861                                     (nVariation == 4)) && (nPart==1))
862                                 rRet.append(" rSub");
863                             else if ((nVariation == 2) && (nPart==2))
864                                 rRet.append(" rSup");
865                             else if ((nVariation == 2) && (nPart==1))
866                                 rRet.append(" rSub");
867                             rRet.append(" {");
868                             break;
869                         case tmDINT:
870                             if (nPart == 0)
871                             {
872                                 if ((nVariation == 2) || (nVariation == 3))
873                                     rRet.append(" llInt");
874                                 else
875                                     rRet.append(" iInt");
876                                 if ( (nVariation != 0) && (nVariation != 2))
877                                 {
878                                     sPush = rRet.makeStringAndClear();
879                                 }
880                             }
881                             if (((nVariation == 1) ||
882                                     (nVariation == 3)) && (nPart==1))
883                                 rRet.append(" rSub");
884                             rRet.append(" {");
885                             break;
886                         case tmTINT:
887                             if (nPart == 0)
888                             {
889                                 if ((nVariation == 2) || (nVariation == 3))
890                                     rRet.append(" lllInt");
891                                 else
892                                     rRet.append(" iiInt");
893                                 if ( (nVariation != 0) && (nVariation != 2))
894                                 {
895                                     sPush = rRet.makeStringAndClear();
896                                 }
897                             }
898                             if (((nVariation == 1) ||
899                                     (nVariation == 3)) && (nPart==1))
900                                 rRet.append(" rSub");
901                             rRet.append(" {");
902                             break;
903                         case tmSSINT:
904                             if (nPart == 0)
905                             {
906                                 if (nVariation == 2)
907                                     rRet.append(" lInt");
908                                 else
909                                     rRet.append(" Int");
910                                 sPush = rRet.makeStringAndClear();
911                             }
912                             if (((nVariation == 1) ||
913                                     (nVariation == 2)) && (nPart==1))
914                                 rRet.append(" cSub");
915                             else if ((nVariation == 0) && (nPart==2))
916                                 rRet.append(" cSup");
917                             else if ((nVariation == 0) && (nPart==1))
918                                 rRet.append(" cSub");
919                             rRet.append(" {");
920                             break;
921                         case tmDSINT:
922                             if (nPart == 0)
923                             {
924                                 if (nVariation == 0)
925                                     rRet.append(" llInt");
926                                 else
927                                     rRet.append(" iInt");
928                                 sPush = rRet.makeStringAndClear();
929                             }
930                             if (nPart==1)
931                                 rRet.append(" cSub");
932                             rRet.append(" {");
933                             break;
934                         case tmTSINT:
935                             if (nPart == 0)
936                             {
937                                 if (nVariation == 0)
938                                     rRet.append(" lllInt");
939                                 else
940                                     rRet.append(" iiInt");
941                                 sPush = rRet.makeStringAndClear();
942                             }
943                             if (nPart==1)
944                                 rRet.append(" cSub");
945                             rRet.append(" {");
946                             break;
947                         case tmUHBRACE:
948                         case tmLHBRACE:
949                             rRet.append(" {");
950                             break;
951                         case tmSUM:
952                             if (nPart == 0)
953                             {
954                                 rRet.append(" Sum");
955                                 if (nVariation != 2)
956                                 {
957                                     sPush = rRet.makeStringAndClear();
958                                 }
959                             }
960                             if ((nVariation == 0) && (nPart==1))
961                                 rRet.append(" cSub");
962                             else if ((nVariation == 1) && (nPart==2))
963                                 rRet.append(" cSup");
964                             else if ((nVariation == 1) && (nPart==1))
965                                 rRet.append(" cSub");
966                             rRet.append(" {");
967                             break;
968                         case tmISUM:
969                             if (nPart == 0)
970                             {
971                                 rRet.append(" Sum");
972                                 sPush = rRet.makeStringAndClear();
973                             }
974                             if ((nVariation == 0) && (nPart==1))
975                                 rRet.append(" rSub");
976                             else if ((nVariation == 1) && (nPart==2))
977                                 rRet.append(" rSup");
978                             else if ((nVariation == 1) && (nPart==1))
979                                 rRet.append(" rSub");
980                             rRet.append(" {");
981                             break;
982                         case tmPROD:
983                             if (nPart == 0)
984                             {
985                                 rRet.append(" Prod");
986                                 if (nVariation != 2)
987                                 {
988                                     sPush = rRet.makeStringAndClear();
989                                 }
990                             }
991                             if ((nVariation == 0) && (nPart==1))
992                                 rRet.append(" cSub");
993                             else if ((nVariation == 1) && (nPart==2))
994                                 rRet.append(" cSup");
995                             else if ((nVariation == 1) && (nPart==1))
996                                 rRet.append(" cSub");
997                             rRet.append(" {");
998                             break;
999                         case tmIPROD:
1000                             if (nPart == 0)
1001                             {
1002                                 rRet.append(" Prod");
1003                                 sPush = rRet.makeStringAndClear();
1004                             }
1005                             if ((nVariation == 0) && (nPart==1))
1006                                 rRet.append(" rSub");
1007                             else if ((nVariation == 1) && (nPart==2))
1008                                 rRet.append(" rSup");
1009                             else if ((nVariation == 1) && (nPart==1))
1010                                 rRet.append(" rSub");
1011                             rRet.append(" {");
1012                             break;
1013                         case tmCOPROD:
1014                             if (nPart == 0)
1015                             {
1016                                 rRet.append(" coProd");
1017                                 if (nVariation != 2)
1018                                 {
1019                                     sPush = rRet.makeStringAndClear();
1020                                 }
1021                             }
1022                             if ((nVariation == 0) && (nPart==1))
1023                                 rRet.append(" cSub");
1024                             else if ((nVariation == 1) && (nPart==2))
1025                                 rRet.append(" cSup");
1026                             else if ((nVariation == 1) && (nPart==1))
1027                                 rRet.append(" cSub");
1028                             rRet.append(" {");
1029                             break;
1030                         case tmICOPROD:
1031                             if (nPart == 0)
1032                             {
1033                                 rRet.append(" coProd");
1034                                 sPush = rRet.makeStringAndClear();
1035                             }
1036                             if ((nVariation == 0) && (nPart==1))
1037                                 rRet.append(" rSub");
1038                             else if ((nVariation == 1) && (nPart==2))
1039                                 rRet.append(" rSup");
1040                             else if ((nVariation == 1) && (nPart==1))
1041                                 rRet.append(" rSub");
1042                             rRet.append(" {");
1043                             break;
1044                         case tmUNION:
1045                             if (nPart == 0)
1046                             {
1047                                 rRet.append(" union"); //union
1048                                 if (nVariation != 2)
1049                                 {
1050                                     sPush = rRet.makeStringAndClear();
1051                                 }
1052                             }
1053                             if ((nVariation == 0) && (nPart==1))
1054                                 rRet.append(" cSub");
1055                             else if ((nVariation == 1) && (nPart==2))
1056                                 rRet.append(" cSup");
1057                             else if ((nVariation == 1) && (nPart==1))
1058                                 rRet.append(" cSub");
1059                             rRet.append(" {");
1060                             break;
1061                         case tmIUNION:
1062                             if (nPart == 0)
1063                             {
1064                                 rRet.append(" union"); //union
1065                                 sPush = rRet.makeStringAndClear();
1066                             }
1067                             if ((nVariation == 0) && (nPart==1))
1068                                 rRet.append(" rSub");
1069                             else if ((nVariation == 1) && (nPart==2))
1070                                 rRet.append(" rSup");
1071                             else if ((nVariation == 1) && (nPart==1))
1072                                 rRet.append(" rSub");
1073                             rRet.append(" {");
1074                             break;
1075                         case tmINTER:
1076                             if (nPart == 0)
1077                             {
1078                                 rRet.append(" intersect"); //intersect
1079                                 if (nVariation != 2)
1080                                 {
1081                                     sPush = rRet.makeStringAndClear();
1082                                 }
1083                             }
1084                             if ((nVariation == 0) && (nPart==1))
1085                                 rRet.append(" cSub");
1086                             else if ((nVariation == 1) && (nPart==2))
1087                                 rRet.append(" cSup");
1088                             else if ((nVariation == 1) && (nPart==1))
1089                                 rRet.append(" cSub");
1090                             rRet.append(" {");
1091                             break;
1092                         case tmIINTER:
1093                             if (nPart == 0)
1094                             {
1095                                 rRet.append(" intersect"); //intersect
1096                                 sPush = rRet.makeStringAndClear();
1097                             }
1098                             if ((nVariation == 0) && (nPart==1))
1099                                 rRet.append(" rSub");
1100                             else if ((nVariation == 1) && (nPart==2))
1101                                 rRet.append(" rSup");
1102                             else if ((nVariation == 1) && (nPart==1))
1103                                 rRet.append(" rSub");
1104                             rRet.append(" {");
1105                             break;
1106                         case tmLIM:
1107                             if ((nVariation == 0) && (nPart==1))
1108                                 rRet.append(" cSup");
1109                             else if ((nVariation == 1) && (nPart==1))
1110                                 rRet.append(" cSub");
1111                             else if ((nVariation == 2) && (nPart==1))
1112                                 rRet.append(" cSub");
1113                             else if ((nVariation == 2) && (nPart==2))
1114                                 rRet.append(" cSup");
1115                             rRet.append(" {");
1116                             break;
1117                         case tmLDIV:
1118                             if (nVariation == 0)
1119                             {
1120                                 if (nPart == 0)
1121                                 {
1122                                     sPush = rRet.makeStringAndClear();
1123                                 }
1124                             }
1125                             rRet.append(" {");
1126                             if (nVariation == 0)
1127                             {
1128                                 if (nPart == 1)
1129                                     rRet.append("alignr ");
1130                             }
1131                             if (nPart == 0)
1132                                 rRet.append("\\lline ");
1133                             if (nVariation == 1)
1134                                 rRet.append("overline ");
1135                             break;
1136                         case tmSLFRACT:
1137                             rRet.append(" {");
1138                             break;
1139                         case tmINTOP:
1140                             if (nPart == 0)
1141                             {
1142                                 sPush = rRet.makeStringAndClear();
1143                             }
1144                             if ((nVariation == 0) && (nPart==0))
1145                                 rRet.append(" rSup");
1146                             else if ((nVariation == 2) && (nPart==1))
1147                                 rRet.append(" rSup");
1148                             else if ((nVariation == 1) && (nPart==0))
1149                                 rRet.append(" rSub");
1150                             else if ((nVariation == 2) && (nPart==0))
1151                                 rRet.append(" rSub");
1152                             rRet.append(" {");
1153                             break;
1154                         case tmSUMOP:
1155                             if (nPart == 0)
1156                             {
1157                                 sPush = rRet.makeStringAndClear();
1158                             }
1159                             if ((nVariation == 0) && (nPart==0))
1160                                 rRet.append(" cSup");
1161                             else if ((nVariation == 2) && (nPart==1))
1162                                 rRet.append(" cSup");
1163                             else if ((nVariation == 1) && (nPart==0))
1164                                 rRet.append(" cSub");
1165                             else if ((nVariation == 2) && (nPart==0))
1166                                 rRet.append(" cSub");
1167                             rRet.append(" {");
1168                             break;
1169                         case tmLSCRIPT:
1170                             if (nPart == 0)
1171                                 rRet.append("\"\"");
1172                             if ((nVariation == 0)
1173                                     || ((nVariation == 2) && (nPart==1)))
1174                                 rRet.append(" lSup");
1175                             else if ((nVariation == 1)
1176                                     || ((nVariation == 2) && (nPart==0)))
1177                                 rRet.append(" lSub");
1178                             rRet.append(" {");
1179                             break;
1180                         case tmDIRAC:
1181                             if (nVariation==0)
1182                             {
1183                                 if (nPart == 0)
1184                                     rRet.append(" langle ");
1185                             }
1186                             else if (nVariation==1)
1187                             {
1188                                 rRet.append(" \\langle ");
1189                                 newline--;
1190                             }
1191                             else if (nVariation==2)
1192                             {
1193                                 rRet.append(" \\lline ");
1194                                 newline--;
1195                             }
1196                             break;
1197                         case tmUARROW:
1198                             if (nVariation == 0)
1199                                 rRet.append(" widevec ");//left below
1200                             else if (nVariation == 1)
1201                                 rRet.append(" widevec ");//right below
1202                             else if (nVariation == 2)
1203                                 rRet.append(" widevec ");//double headed below
1204                             rRet.append(" {");
1205                             break;
1206                         case tmOARROW:
1207                             if (nVariation == 0)
1208                                 rRet.append(" widevec ");//left above
1209                             else if (nVariation == 1)
1210                                 rRet.append(" widevec ");//right above
1211                             else if (nVariation == 2)
1212                                 rRet.append(" widevec ");//double headed above
1213                             rRet.append(" {");
1214                             break;
1215                         default:
1216                             break;
1217                         }
1218                         sal_Int16 nOldCurSize=nCurSize;
1219                         sal_Int32 nSizeStartPos = rRet.getLength();
1220                         HandleSize( nLSize, nDSize, nSetSize );
1221                         bRet = HandleRecords( nLevel+1 );
1222                         while (nSetSize)
1223                         {
1224                             bool bOk=false;
1225                             sal_Int32 nI = rRet.lastIndexOf('{');
1226                             if (nI != -1)
1227                             {
1228                                 for(nI=nI+1;nI<rRet.getLength();nI++)
1229                                     if (rRet[nI] != ' ')
1230                                     {
1231                                         bOk=true;
1232                                         break;
1233                                     }
1234                             }
1235                             else
1236                                 bOk=true;
1237 
1238                             if (bOk)
1239                                 rRet.append("} ");
1240                             else if (rRet.getLength() > nSizeStartPos)
1241                                 rRet = rRet.truncate(nSizeStartPos);
1242                             nSetSize--;
1243                             nCurSize=nOldCurSize;
1244                         }
1245 
1246 
1247                         HandleMatrixSeparator(nMatrixRows,nMatrixCols,
1248                             nCurCol,nCurRow);
1249 
1250                         switch (nSelector)
1251                         {
1252                         case tmANGLE:
1253                             if (nVariation==0)
1254                                 rRet.append(" rangle ");
1255                             else if (nVariation==2)
1256                                 rRet.append(" \\rangle ");
1257                             break;
1258                         case tmPAREN:
1259                             if (nVariation==0)
1260                                 rRet.append(" right )");
1261                             else if (nVariation==2)
1262                                 rRet.append("\\)");
1263                             break;
1264                         case tmBRACE:
1265                             if ((nVariation==0) || (nVariation==2))
1266                                 rRet.append(" right rbrace ");
1267                             else
1268                                 rRet.append(" right none ");
1269                             break;
1270                         case tmBRACK:
1271                             if (nVariation==0)
1272                                 rRet.append(" right ]");
1273                             else if (nVariation==2)
1274                                 rRet.append("\\]");
1275                             break;
1276                         case tmBAR:
1277                             if (nVariation==0)
1278                                 rRet.append(" rline ");
1279                             else if (nVariation==2)
1280                                 rRet.append(" \\rline ");
1281                             break;
1282                         case tmDBAR:
1283                             if (nVariation==0)
1284                                 rRet.append(" rdline ");
1285                             else if (nVariation==2)
1286                                 rRet.append(" \\rdline ");
1287                             break;
1288                         case tmFLOOR:
1289                             if (nVariation == 0 || nVariation & 0x02) // tvFENCE_R
1290                                 rRet.append(" right rfloor ");
1291                             else
1292                                 rRet.append(" right none ");
1293                             break;
1294                         case tmCEILING:
1295                             if (nVariation==0)
1296                                 rRet.append(" rceil ");
1297                             else if (nVariation==2)
1298                                 rRet.append(" \\rceil ");
1299                             break;
1300                         case tmLBLB:
1301                         case tmRBLB:
1302                             rRet.append("\\[");
1303                             break;
1304                         case tmRBRB:
1305                         case tmLPRB:
1306                             rRet.append("\\]");
1307                             break;
1308                         case tmROOT:
1309                             rRet.append("} ");
1310                             if (nVariation == 1)
1311                             {
1312                                 if (nPart == 0)
1313                                 {
1314                                     newline--;
1315                                     sMainTerm = rRet.makeStringAndClear();
1316                                 }
1317                                 else if (nPart == 1)
1318                                 {
1319                                     rRet.insert(0, sPush);
1320                                     rRet.append(sMainTerm);
1321                                     sPush.clear();
1322                                     sMainTerm.clear();
1323                                 }
1324                             }
1325                             else
1326                             {
1327                                 if (nPart == 0)
1328                                     newline--;
1329                             }
1330                             nPart++;
1331                             break;
1332                         case tmLBRP:
1333                             rRet.append("\\)");
1334                             break;
1335                         case tmFRACT:
1336                             rRet.append("} ");
1337                             if (nPart == 0)
1338                                 newline--;
1339                             else
1340                                 rRet.append("} ");
1341                             nPart++;
1342                             break;
1343                         case tmSCRIPT:
1344                             {
1345                             if ((nPart == 0) &&
1346                                     ((nVariation == 2) || (nVariation == 1)))
1347                                 newline--;
1348 
1349                             bool bOk=false;
1350                             sal_Int32 nI = rRet.lastIndexOf('{');
1351                             if (nI != -1)
1352                             {
1353                                 for(nI=nI+1;nI<rRet.getLength();nI++)
1354                                     if (rRet[nI] != ' ')
1355                                     {
1356                                         bOk=true;
1357                                         break;
1358                                     }
1359                             }
1360                             else
1361                                 bOk=true;
1362 
1363                             if (bOk)
1364                                 rRet.append("} ");
1365                             else if (rRet.getLength() > nSubSupStartPos)
1366                                 rRet = rRet.truncate(nSubSupStartPos);
1367                             nPart++;
1368                             }
1369                             break;
1370                         case tmLSCRIPT:
1371                             if ((nPart == 0) &&
1372                                     ((nVariation == 2) || (nVariation == 1)))
1373                                 newline--;
1374                             rRet.append("} ");
1375                             nPart++;
1376                             break;
1377                         case tmUARROW:
1378                         case tmOARROW:
1379                             rRet.append("} ");
1380                             break;
1381                         case tmUBAR:
1382                         case tmOBAR:
1383                             rRet.append("}} ");
1384                             break;
1385                         case tmLARROW:
1386                         case tmRARROW:
1387                         case tmBARROW:
1388                             if (nPart == 0)
1389                             {
1390                                 newline--;
1391                                 rRet.append("} ");
1392                             }
1393                             nPart++;
1394                             break;
1395                         case tmUHBRACE:
1396                             rRet.append("} ");
1397                             if (nPart == 0)
1398                             {
1399                                 newline--;
1400                                 rRet.append("overbrace");
1401                             }
1402                             nPart++;
1403                             break;
1404                         case tmLHBRACE:
1405                             rRet.append("} ");
1406                             if (nPart == 0)
1407                             {
1408                                 newline--;
1409                                 rRet.append("underbrace");
1410                             }
1411                             nPart++;
1412                             break;
1413                         case tmLIM:
1414                             if (nPart==0)
1415                                 newline--;
1416                             else if ((nPart==1) &&
1417                                     ((nVariation == 2) || (nVariation == 1)))
1418                                 newline--;
1419                             rRet.append("} ");
1420                             nPart++;
1421                             break;
1422                         case tmLDIV:
1423                             rRet.append("} ");
1424                             if (nVariation == 0)
1425                             {
1426                                 if (nPart == 0)
1427                                 {
1428                                     sMainTerm = rRet.makeStringAndClear();
1429                                 }
1430                                 else if (nPart == 1)
1431                                 {
1432                                     rRet.insert(0, sPush);
1433                                     rRet.append(" over ").append(sMainTerm);
1434                                     sPush.clear();
1435                                     sMainTerm.clear();
1436                                 }
1437                             }
1438                             if (nPart == 0)
1439                                 newline--;
1440                             nPart++;
1441                             break;
1442                         case tmSLFRACT:
1443                             rRet.append("} ");
1444                             if (nPart == 0)
1445                             {
1446                                 newline--;
1447                                 switch (nVariation)
1448                                 {
1449                                 case 1:
1450                                     rRet.append("slash");
1451                                     break;
1452                                 default:
1453                                     rRet.append("wideslash");
1454                                     break;
1455                                 }
1456                             }
1457                             nPart++;
1458                             break;
1459                         case tmSUM:
1460                         case tmISUM:
1461                         case tmPROD:
1462                         case tmIPROD:
1463                         case tmCOPROD:
1464                         case tmICOPROD:
1465                         case tmUNION:
1466                         case tmIUNION:
1467                         case tmINTER:
1468                         case tmIINTER:
1469                             rRet.append("} ");
1470                             if (nPart == 0)
1471                             {
1472                                 if (nVariation != 2)
1473                                 {
1474                                     sMainTerm = rRet.makeStringAndClear();
1475                                 }
1476                                 newline--;
1477                             }
1478                             else if ((nPart == 1) && (nVariation == 0))
1479                             {
1480                                 rRet.insert(0, sPush);
1481                                 rRet.append(sMainTerm);
1482                                 sPush.clear();
1483                                 sMainTerm.clear();
1484                                 newline--;
1485                             }
1486                             else if ((nPart == 1) && (nVariation == 1))
1487                                 newline--;
1488                             else if ((nPart == 2) && (nVariation == 1))
1489                             {
1490                                 rRet.insert(0, sPush);
1491                                 rRet.append(sMainTerm);
1492                                 sPush.clear();
1493                                 sMainTerm.clear();
1494                                 newline--;
1495                             }
1496                             nPart++;
1497                             break;
1498                         case tmSINT:
1499                             rRet.append("} ");
1500                             if (nPart == 0)
1501                             {
1502                                 if ((nVariation != 0) && (nVariation != 3))
1503                                 {
1504                                     sMainTerm = rRet.makeStringAndClear();
1505                                 }
1506                                 newline--;
1507                             }
1508                             else if ((nPart == 1) &&
1509                                     ((nVariation == 1) || (nVariation==4)))
1510                             {
1511                                 rRet.insert(0, sPush);
1512                                 rRet.append(sMainTerm);
1513                                 sPush.clear();
1514                                 sMainTerm.clear();
1515                                 newline--;
1516                             }
1517                             else if ((nPart == 1) && (nVariation == 2))
1518                                 newline--;
1519                             else if ((nPart == 2) && (nVariation == 2))
1520                             {
1521                                 rRet.insert(0, sPush);
1522                                 rRet.append(sMainTerm);
1523                                 sPush.clear();
1524                                 sMainTerm.clear();
1525                                 newline--;
1526                             }
1527                             nPart++;
1528                             break;
1529                         case tmDINT:
1530                         case tmTINT:
1531                             rRet.append("} ");
1532                             if (nPart == 0)
1533                             {
1534                                 if ((nVariation != 0) && (nVariation != 2))
1535                                 {
1536                                     sMainTerm = rRet.makeStringAndClear();
1537                                 }
1538                                 newline--;
1539                             }
1540                             else if ((nPart == 1) &&
1541                                     ((nVariation == 1) || (nVariation==3)))
1542                             {
1543                                 rRet.insert(0, sPush);
1544                                 rRet.append(sMainTerm);
1545                                 sPush.clear();
1546                                 sMainTerm.clear();
1547                                 newline--;
1548                             }
1549                             nPart++;
1550                             break;
1551                         case tmSSINT:
1552                             rRet.append("} ");
1553                             if (nPart == 0)
1554                             {
1555                                 sMainTerm = rRet.makeStringAndClear();
1556                                 newline--;
1557                             }
1558                             else if ((nPart == 1) &&
1559                                     ((nVariation == 1) || (nVariation==2)))
1560                             {
1561                                 rRet.insert(0, sPush);
1562                                 rRet.append(sMainTerm);
1563                                 sPush.clear();
1564                                 sMainTerm.clear();
1565                                 newline--;
1566                             }
1567                             else if ((nPart == 1) && (nVariation == 0))
1568                                 newline--;
1569                             else if ((nPart == 2) && (nVariation == 0))
1570                             {
1571                                 rRet.insert(0, sPush);
1572                                 rRet.append(sMainTerm);
1573                                 sPush.clear();
1574                                 sMainTerm.clear();
1575                                 newline--;
1576                             }
1577                             nPart++;
1578                             break;
1579                         case tmDSINT:
1580                         case tmTSINT:
1581                             rRet.append("} ");
1582                             if (nPart == 0)
1583                             {
1584                                 sMainTerm = rRet.makeStringAndClear();
1585                                 newline--;
1586                             }
1587                             else if (nPart == 1)
1588                             {
1589                                 rRet.insert(0, sPush);
1590                                 rRet.append(sMainTerm);
1591                                 sPush.clear();
1592                                 sMainTerm.clear();
1593                                 newline--;
1594                             }
1595                             nPart++;
1596                             break;
1597                         case tmINTOP:
1598                         case tmSUMOP:
1599                             rRet.append("} ");
1600 
1601                             if ((nPart == 0) &&
1602                                     ((nVariation == 0) || (nVariation == 1)))
1603                             {
1604                                 sMainTerm = rRet.makeStringAndClear();
1605                                 newline--;
1606                             }
1607                             else if ((nPart == 0) && (nVariation == 2))
1608                                 newline--;
1609                             else if ((nPart == 1) && (nVariation == 2))
1610                             {
1611                                 sMainTerm = rRet.makeStringAndClear();
1612                                 newline--;
1613                             }
1614                             else if ((nPart == 2) || ((nPart == 1) &&
1615                                     (nVariation == 0 || nVariation == 1)))
1616                             {
1617                                 rRet.insert(0, sPush);
1618                                 rRet.append(sMainTerm);
1619                                 sPush.clear();
1620                                 sMainTerm.clear();
1621                             }
1622                             nPart++;
1623                             break;
1624                         case tmDIRAC:
1625                             if (nVariation==0)
1626                             {
1627                                 if (nPart == 0)
1628                                 {
1629                                     newline--; //there is another term to arrive
1630                                     rRet.append(" mline ");
1631                                 }
1632                                 else
1633                                     rRet.append(" rangle ");
1634                             }
1635                             else if (nVariation==1)
1636                                 rRet.append(" \\lline ");
1637                             else if (nVariation==2)
1638                                 rRet.append(" \\rangle ");
1639                             nPart++;
1640                             break;
1641                         default:
1642                             break;
1643                         }
1644                         bSilent = true; //Skip the optional brackets and/or
1645                                         //symbols that follow some of these
1646                                         //records. Foo Data.
1647 
1648                         /*In matrices and piles we cannot separate equation
1649                          *lines with the newline keyword*/
1650                         if (nMatrixCols==0)
1651                             newline++;
1652                     }
1653                 }
1654                 break;
1655             case CHAR:
1656                 if (xfLMOVE(nTag))
1657                     HandleNudge();
1658                 bRet = HandleChar( nTextStart, nSetSize, nLevel, nTag, nSelector, nVariation, bSilent );
1659                 break;
1660             case TMPL:
1661                 if (xfLMOVE(nTag))
1662                     HandleNudge();
1663                 bRet = HandleTemplate( nLevel, nSelector, nVariation, nLastTemplateBracket );
1664                 break;
1665             case PILE:
1666                 if (xfLMOVE(nTag))
1667                     HandleNudge();
1668                 bRet = HandlePile( nSetAlign, nLevel, nSelector, nVariation );
1669                 HandleMatrixSeparator( nMatrixRows, nMatrixCols, nCurCol, nCurRow );
1670                 break;
1671             case MATRIX:
1672                 if (xfLMOVE(nTag))
1673                     HandleNudge();
1674                 bRet = HandleMatrix( nLevel, nSelector, nVariation );
1675                 HandleMatrixSeparator( nMatrixRows, nMatrixCols, nCurCol, nCurRow );
1676                 break;
1677             case EMBEL:
1678                 if (xfLMOVE(nTag))
1679                     HandleNudge();
1680                 HandleEmblishments();
1681                 break;
1682             case RULER:
1683                 pS->ReadUChar( nTabStops );
1684                 for (i=0;i<nTabStops;i++)
1685                 {
1686                     pS->ReadUChar( nTabType );
1687                     pS->ReadUInt16( nTabOffset );
1688                 }
1689                 SAL_WARN("starmath", "Not seen in the wild Equation Ruler Field");
1690                 break;
1691             case FONT:
1692                 {
1693                     MathTypeFont aFont;
1694                     pS->ReadUChar( aFont.nTface );
1695                     /*
1696                     The typeface number is the negative (which makes it
1697                     positive) of the typeface value (unbiased) that appears in
1698                     CHAR records that might follow a given FONT record
1699                     */
1700                     aFont.nTface = 128-aFont.nTface;
1701                     pS->ReadUChar( aFont.nStyle );
1702                     aUserStyles.insert(aFont);
1703                     // read font name
1704                     while(true)
1705                     {
1706                         sal_Char nChar8(0);
1707                         pS->ReadChar( nChar8 );
1708                         if (nChar8 == 0)
1709                             break;
1710                     }
1711                 }
1712                 break;
1713             case SIZE:
1714                 HandleSetSize();
1715                 break;
1716             case 10:
1717             case 11:
1718             case 12:
1719             case 13:
1720             case 14:
1721                 nLSize=nRecord-10;
1722                 break;
1723             case END:
1724             default:
1725                 break;
1726         }
1727     }
1728     while (nRecord != END && !pS->eof());
1729     while (nSetSize)
1730     {
1731         rRet.append("}");
1732         nSetSize--;
1733     }
1734     return bRet;
1735 }
1736 
1737 /*Simply determine if we are at the end of a record or the end of a line,
1738  *with fiddly logic to see if we are in a matrix or a pile or neither
1739 
1740  Note we cannot tell until after the event that this is the last entry
1741  of a pile, so we must strip the last separator of a pile after this
1742  is detected in the PILE handler
1743  */
HandleMatrixSeparator(int nMatrixRows,int nMatrixCols,int & rCurCol,int & rCurRow)1744 void MathType::HandleMatrixSeparator(int nMatrixRows,int nMatrixCols,
1745     int &rCurCol,int &rCurRow)
1746 {
1747     if (nMatrixRows==0)
1748         return;
1749 
1750     if (rCurCol == nMatrixCols-1)
1751     {
1752         if (rCurRow != nMatrixRows-1)
1753             rRet.append(" {} ##\n");
1754         if (nMatrixRows!=-1)
1755         {
1756             rCurCol=0;
1757             rCurRow++;
1758         }
1759     }
1760     else
1761     {
1762         rRet.append(" {} # ");
1763         if (nMatrixRows!=-1)
1764             rCurCol++;
1765         else
1766             rRet.append("\n");
1767     }
1768 }
1769 
1770 /* set the alignment of the following term, but starmath currently
1771  * cannot handle vertical alignment */
HandleAlign(sal_uInt8 nHorAlign,int & rSetAlign)1772 void MathType::HandleAlign(sal_uInt8 nHorAlign, int &rSetAlign)
1773 {
1774     switch(nHorAlign)
1775     {
1776     case 1:
1777     default:
1778         rRet.append("alignl {");
1779         break;
1780     case 2:
1781         rRet.append("alignc {");
1782         break;
1783     case 3:
1784         rRet.append("alignr {");
1785         break;
1786     }
1787     rSetAlign++;
1788 }
1789 
1790 /* set size of text, complexity due to overuse of signedness as a flag
1791  * indicator by mathtype file format*/
HandleSize(sal_Int16 nLstSize,sal_Int16 nDefSize,int & rSetSize)1792 bool MathType::HandleSize(sal_Int16 nLstSize,sal_Int16 nDefSize, int &rSetSize)
1793 {
1794     const sal_Int16 nDefaultSize = 12;
1795     bool bRet=false;
1796     if (nLstSize < 0)
1797     {
1798         if ((-nLstSize/32 != nDefaultSize) && (-nLstSize/32 != nCurSize))
1799         {
1800             if (rSetSize)
1801             {
1802                 rSetSize--;
1803                 rRet.append("}");
1804                 bRet=true;
1805             }
1806             if (-nLstSize/32 != nLastSize)
1807             {
1808                 nLastSize = nCurSize;
1809                 rRet.append(" size ");
1810                 rRet.append(OUString::number(-nLstSize/32));
1811                 rRet.append("{");
1812                 bRet=true;
1813                 rSetSize++;
1814             }
1815             nCurSize = -nLstSize/32;
1816         }
1817     }
1818     else
1819     {
1820         /*sizetable should theoretically be filled with the default sizes
1821          *of the various font groupings matching starmaths equivalents
1822          in aTypeFaces, and a test would be done to see if the new font
1823          size would be the same as what starmath would have chosen for
1824          itself anyway in which case the size setting could be ignored*/
1825         nLstSize = aSizeTable.at(nLstSize);
1826         nLstSize = nLstSize + nDefSize;
1827         if (nLstSize != nCurSize)
1828         {
1829             if (rSetSize)
1830             {
1831                 rSetSize--;
1832                 rRet.append("}");
1833                 bRet=true;
1834             }
1835             if (nLstSize != nLastSize)
1836             {
1837                 nLastSize = nCurSize;
1838                 rRet.append(" size ");
1839                 rRet.append(OUString::number(nLstSize));
1840                 rRet.append("{");
1841                 bRet=true;
1842                 rSetSize++;
1843             }
1844             nCurSize = nLstSize;
1845         }
1846     }
1847     return bRet;
1848 }
1849 
ConvertFromStarMath(SfxMedium & rMedium)1850 bool MathType::ConvertFromStarMath( SfxMedium& rMedium )
1851 {
1852     if (!pTree)
1853         return false;
1854 
1855     SvStream *pStream = rMedium.GetOutStream();
1856     if ( pStream )
1857     {
1858         tools::SvRef<SotStorage> pStor = new SotStorage( pStream, false );
1859 
1860         SvGlobalName aGName(MSO_EQUATION3_CLASSID);
1861         pStor->SetClass( aGName, SotClipboardFormatId::NONE, "Microsoft Equation 3.0");
1862 
1863         static sal_uInt8 const aCompObj[] = {
1864             0x01, 0x00, 0xFE, 0xFF, 0x03, 0x0A, 0x00, 0x00,
1865             0xFF, 0xFF, 0xFF, 0xFF, 0x02, 0xCE, 0x02, 0x00,
1866             0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00,
1867             0x00, 0x00, 0x00, 0x46, 0x17, 0x00, 0x00, 0x00,
1868             0x4D, 0x69, 0x63, 0x72, 0x6F, 0x73, 0x6F, 0x66,
1869             0x74, 0x20, 0x45, 0x71, 0x75, 0x61, 0x74, 0x69,
1870             0x6F, 0x6E, 0x20, 0x33, 0x2E, 0x30, 0x00, 0x0C,
1871             0x00, 0x00, 0x00, 0x44, 0x53, 0x20, 0x45, 0x71,
1872             0x75, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x00, 0x0B,
1873             0x00, 0x00, 0x00, 0x45, 0x71, 0x75, 0x61, 0x74,
1874             0x69, 0x6F, 0x6E, 0x2E, 0x33, 0x00, 0xF4, 0x39,
1875             0xB2, 0x71, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1876             0x00, 0x00, 0x00, 0x00, 0x00, 0x00
1877         };
1878         tools::SvRef<SotStorageStream> xStor( pStor->OpenSotStream("\1CompObj"));
1879         xStor->WriteBytes(aCompObj, sizeof(aCompObj));
1880 
1881         static sal_uInt8 const aOle[] = {
1882             0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00,
1883             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1884             0x00, 0x00, 0x00, 0x00
1885             };
1886         tools::SvRef<SotStorageStream> xStor2( pStor->OpenSotStream("\1Ole"));
1887         xStor2->WriteBytes(aOle, sizeof(aOle));
1888         xStor.clear();
1889         xStor2.clear();
1890 
1891         tools::SvRef<SotStorageStream> xSrc = pStor->OpenSotStream("Equation Native");
1892         if ( (!xSrc.is()) || (ERRCODE_NONE != xSrc->GetError()))
1893             return false;
1894 
1895         pS = xSrc.get();
1896         pS->SetEndian( SvStreamEndian::LITTLE );
1897 
1898         pS->SeekRel(EQNOLEFILEHDR_SIZE); //Skip 28byte Header and fill it in later
1899         pS->WriteUChar( 0x03 );
1900         pS->WriteUChar( 0x01 );
1901         pS->WriteUChar( 0x01 );
1902         pS->WriteUChar( 0x03 );
1903         pS->WriteUChar( 0x00 );
1904         sal_uInt32 nSize = pS->Tell();
1905         nPendingAttributes=0;
1906 
1907         HandleNodes(pTree, 0);
1908         pS->WriteUChar( END );
1909 
1910         nSize = pS->Tell()-nSize;
1911         pS->Seek(0);
1912         EQNOLEFILEHDR aHdr(nSize+4+1);
1913         aHdr.Write(pS);
1914 
1915         pStor->Commit();
1916     }
1917 
1918     return true;
1919 }
1920 
1921 
HandleNodes(SmNode * pNode,int nLevel)1922 void MathType::HandleNodes(SmNode *pNode,int nLevel)
1923 {
1924     switch(pNode->GetType())
1925     {
1926         case SmNodeType::Attribut:
1927             HandleAttributes(pNode,nLevel);
1928             break;
1929         case SmNodeType::Text:
1930             HandleText(pNode);
1931             break;
1932         case SmNodeType::VerticalBrace:
1933             HandleVerticalBrace(pNode,nLevel);
1934             break;
1935         case SmNodeType::Brace:
1936             HandleBrace(pNode,nLevel);
1937             break;
1938         case SmNodeType::Oper:
1939             HandleOperator(pNode,nLevel);
1940             break;
1941         case SmNodeType::BinVer:
1942             HandleFractions(pNode,nLevel);
1943             break;
1944         case SmNodeType::Root:
1945             HandleRoot(pNode,nLevel);
1946             break;
1947         case SmNodeType::Special:
1948             {
1949             SmTextNode *pText = static_cast<SmTextNode *>(pNode);
1950             //if the token str and the result text are the same then this
1951             //is to be seen as text, else assume it's a mathchar
1952             if (pText->GetText() == pText->GetToken().aText)
1953                 HandleText(pText);
1954             else
1955                 HandleMath(pText);
1956             }
1957             break;
1958         case SmNodeType::Math:
1959         case SmNodeType::MathIdent:
1960             HandleMath(pNode);
1961             break;
1962         case SmNodeType::SubSup:
1963             HandleSubSupScript(pNode,nLevel);
1964             break;
1965         case SmNodeType::Expression:
1966         {
1967             size_t nSize = pNode->GetNumSubNodes();
1968             for (size_t i = 0; i < nSize; ++i)
1969             {
1970                 if (SmNode *pTemp = pNode->GetSubNode(i))
1971                     HandleNodes(pTemp,nLevel+1);
1972             }
1973             break;
1974         }
1975         case SmNodeType::Table:
1976             //Root Node, PILE equivalent, i.e. vertical stack
1977             HandleTable(pNode,nLevel);
1978             break;
1979         case SmNodeType::Matrix:
1980             HandleSmMatrix(static_cast<SmMatrixNode *>(pNode),nLevel);
1981             break;
1982         case SmNodeType::Line:
1983         {
1984             pS->WriteUChar( 0x0a );
1985             pS->WriteUChar( LINE );
1986             size_t nSize = pNode->GetNumSubNodes();
1987             for (size_t i = 0; i < nSize; ++i)
1988             {
1989                 if (SmNode *pTemp = pNode->GetSubNode(i))
1990                     HandleNodes(pTemp,nLevel+1);
1991             }
1992             pS->WriteUChar( END );
1993             break;
1994         }
1995         case SmNodeType::Align:
1996             HandleMAlign(pNode,nLevel);
1997             break;
1998         case SmNodeType::Blank:
1999             pS->WriteUChar( CHAR );
2000             pS->WriteUChar( 0x98 );
2001             if (pNode->GetToken().eType == TSBLANK)
2002                 pS->WriteUInt16( 0xEB04 );
2003             else
2004                 pS->WriteUInt16( 0xEB05 );
2005             break;
2006         default:
2007         {
2008             size_t nSize = pNode->GetNumSubNodes();
2009             for (size_t i = 0; i < nSize; ++i)
2010             {
2011                 if (SmNode *pTemp = pNode->GetSubNode(i))
2012                     HandleNodes(pTemp,nLevel+1);
2013             }
2014             break;
2015         }
2016     }
2017 }
2018 
2019 
StartTemplate(sal_uInt16 nSelector,sal_uInt16 nVariation)2020 int MathType::StartTemplate(sal_uInt16 nSelector,sal_uInt16 nVariation)
2021 {
2022     int nOldPending=nPendingAttributes;
2023     pS->WriteUChar( TMPL ); //Template
2024     pS->WriteUChar( nSelector ); //selector
2025     pS->WriteUChar( nVariation ); //variation
2026     pS->WriteUChar( 0x00 ); //options
2027     pS->WriteUChar( LINE );
2028     //there's just no way we can now handle any character
2029     //attributes (from mathtypes perspective) centered
2030     //over an expression but above template attribute
2031     //such as widevec and similar constructs
2032     //we have to drop them
2033     nPendingAttributes=0;
2034     return nOldPending;
2035 }
2036 
EndTemplate(int nOldPendingAttributes)2037 void MathType::EndTemplate(int nOldPendingAttributes)
2038 {
2039     pS->WriteUChar( END ); //end line
2040     pS->WriteUChar( END ); //end template
2041     nPendingAttributes=nOldPendingAttributes;
2042 }
2043 
2044 
HandleSmMatrix(SmMatrixNode * pMatrix,int nLevel)2045 void MathType::HandleSmMatrix(SmMatrixNode *pMatrix,int nLevel)
2046 {
2047     pS->WriteUChar( MATRIX );
2048     pS->WriteUChar( 0x00 ); //vAlign ?
2049     pS->WriteUChar( 0x00 ); //h_just
2050     pS->WriteUChar( 0x00 ); //v_just
2051     pS->WriteUChar( pMatrix->GetNumRows() ); //v_just
2052     pS->WriteUChar( pMatrix->GetNumCols() ); //v_just
2053     int nBytes=(pMatrix->GetNumRows()+1)*2/8;
2054     if (((pMatrix->GetNumRows()+1)*2)%8)
2055         nBytes++;
2056     for (int j = 0; j < nBytes; j++)
2057         pS->WriteUChar( 0x00 ); //row_parts
2058     nBytes=(pMatrix->GetNumCols()+1)*2/8;
2059     if (((pMatrix->GetNumCols()+1)*2)%8)
2060         nBytes++;
2061     for (int k = 0; k < nBytes; k++)
2062         pS->WriteUChar( 0x00 ); //col_parts
2063     size_t nSize = pMatrix->GetNumSubNodes();
2064     for (size_t i = 0; i < nSize; ++i)
2065     {
2066         if (SmNode *pTemp = pMatrix->GetSubNode(i))
2067         {
2068             pS->WriteUChar( LINE ); //line
2069             HandleNodes(pTemp,nLevel+1);
2070             pS->WriteUChar( END ); //end line
2071         }
2072     }
2073     pS->WriteUChar( END );
2074 }
2075 
2076 
2077 //Root Node, PILE equivalent, i.e. vertical stack
HandleTable(SmNode * pNode,int nLevel)2078 void MathType::HandleTable(SmNode *pNode,int nLevel)
2079 {
2080     size_t nSize = pNode->GetNumSubNodes();
2081     //The root of the starmath is a table, if
2082     //we convert this them each iteration of
2083     //conversion from starmath to mathtype will
2084     //add an extra unnecessary level to the
2085     //mathtype output stack which would grow
2086     //without bound in a multi step conversion
2087 
2088     if (nLevel == 0)
2089         pS->WriteUChar( 0x0A ); //initial size
2090 
2091     if ( nLevel || (nSize >1))
2092     {
2093         pS->WriteUChar( PILE );
2094         pS->WriteUChar( nHAlign ); //vAlign ?
2095         pS->WriteUChar( 0x01 ); //hAlign
2096     }
2097 
2098     for (size_t i = 0; i < nSize; ++i)
2099     {
2100         if (SmNode *pTemp = pNode->GetSubNode(i))
2101         {
2102             pS->WriteUChar( LINE );
2103             HandleNodes(pTemp,nLevel+1);
2104             pS->WriteUChar( END );
2105         }
2106     }
2107     if (nLevel || (nSize>1))
2108         pS->WriteUChar( END );
2109 }
2110 
2111 
HandleRoot(SmNode * pNode,int nLevel)2112 void MathType::HandleRoot(SmNode *pNode,int nLevel)
2113 {
2114     SmNode *pTemp;
2115     pS->WriteUChar( TMPL ); //Template
2116     pS->WriteUChar( 0x0D ); //selector
2117     if (pNode->GetSubNode(0))
2118         pS->WriteUChar( 0x01 ); //variation
2119     else
2120         pS->WriteUChar( 0x00 ); //variation
2121     pS->WriteUChar( 0x00 ); //options
2122 
2123     if (nullptr != (pTemp = pNode->GetSubNode(2)))
2124     {
2125         pS->WriteUChar( LINE ); //line
2126         HandleNodes(pTemp,nLevel+1);
2127         pS->WriteUChar( END );
2128     }
2129 
2130     if (nullptr != (pTemp = pNode->GetSubNode(0)))
2131     {
2132         pS->WriteUChar( LINE ); //line
2133         HandleNodes(pTemp,nLevel+1);
2134         pS->WriteUChar( END );
2135     }
2136     else
2137         pS->WriteUChar( LINE|0x10 ); //dummy line
2138 
2139 
2140     pS->WriteUChar( END );
2141 }
2142 
HandleCScript(SmNode * pNode,SmNode * pContent,int nLevel,sal_uInt64 * pPos,bool bTest)2143 sal_uInt8 MathType::HandleCScript(SmNode *pNode,SmNode *pContent,int nLevel,
2144     sal_uInt64 *pPos,bool bTest)
2145 {
2146     sal_uInt8 nVariation2=0xff;
2147 
2148     if (bTest && pNode->GetSubNode(CSUP+1))
2149     {
2150         nVariation2=0;
2151         if (pNode->GetSubNode(CSUB+1))
2152             nVariation2=2;
2153     }
2154     else if (pNode->GetSubNode(CSUB+1))
2155         nVariation2=1;
2156 
2157     if (nVariation2!=0xff)
2158     {
2159         if (pPos)
2160             *pPos = pS->Tell();
2161         pS->WriteUChar( TMPL ); //Template
2162         pS->WriteUChar( 0x2B ); //selector
2163         pS->WriteUChar( nVariation2 );
2164         pS->WriteUChar( 0x00 ); //options
2165 
2166         if (pContent)
2167         {
2168             pS->WriteUChar( LINE ); //line
2169             HandleNodes(pContent,nLevel+1);
2170             pS->WriteUChar( END ); //line
2171         }
2172         else
2173             pS->WriteUChar( LINE|0x10 );
2174 
2175         pS->WriteUChar( 0x0B );
2176 
2177         SmNode *pTemp;
2178         if (nullptr != (pTemp = pNode->GetSubNode(CSUB+1)))
2179         {
2180             pS->WriteUChar( LINE ); //line
2181             HandleNodes(pTemp,nLevel+1);
2182             pS->WriteUChar( END ); //line
2183         }
2184         else
2185             pS->WriteUChar( LINE|0x10 );
2186         if (bTest && nullptr != (pTemp = pNode->GetSubNode(CSUP+1)))
2187         {
2188             pS->WriteUChar( LINE ); //line
2189             HandleNodes(pTemp,nLevel+1);
2190             pS->WriteUChar( END ); //line
2191         }
2192         else
2193             pS->WriteUChar( LINE|0x10 );
2194     }
2195     return nVariation2;
2196 }
2197 
2198 
2199 /*
2200  Sub and Sup scripts and another problem area, StarMath
2201  can have all possible options used at the same time, whereas
2202  Mathtype cannot. The ordering of the nodes for each system
2203  is quite different as well leading to some complexity
2204  */
HandleSubSupScript(SmNode * pNode,int nLevel)2205 void MathType::HandleSubSupScript(SmNode *pNode,int nLevel)
2206 {
2207     sal_uInt8 nVariation=0xff;
2208     if (pNode->GetSubNode(LSUP+1))
2209     {
2210         nVariation=0;
2211         if (pNode->GetSubNode(LSUB+1))
2212             nVariation=2;
2213     }
2214     else if ( nullptr != pNode->GetSubNode(LSUB+1) )
2215         nVariation=1;
2216 
2217     SmNode *pTemp;
2218     if (nVariation!=0xff)
2219     {
2220         pS->WriteUChar( TMPL ); //Template
2221         pS->WriteUChar( 0x2c ); //selector
2222         pS->WriteUChar( nVariation );
2223         pS->WriteUChar( 0x00 ); //options
2224         pS->WriteUChar( 0x0B );
2225 
2226         if (nullptr != (pTemp = pNode->GetSubNode(LSUB+1)))
2227         {
2228             pS->WriteUChar( LINE ); //line
2229             HandleNodes(pTemp,nLevel+1);
2230             pS->WriteUChar( END ); //line
2231         }
2232         else
2233             pS->WriteUChar( LINE|0x10 );
2234         if (nullptr != (pTemp = pNode->GetSubNode(LSUP+1)))
2235         {
2236             pS->WriteUChar( LINE ); //line
2237             HandleNodes(pTemp,nLevel+1);
2238             pS->WriteUChar( END ); //line
2239         }
2240         else
2241             pS->WriteUChar( LINE|0x10 );
2242         pS->WriteUChar( END );
2243         nVariation=0xff;
2244     }
2245 
2246 
2247     sal_uInt8 nVariation2=HandleCScript(pNode,nullptr,nLevel);
2248 
2249     if (nullptr != (pTemp = pNode->GetSubNode(0)))
2250     {
2251         HandleNodes(pTemp,nLevel+1);
2252     }
2253 
2254     if (nVariation2 != 0xff)
2255         pS->WriteUChar( END );
2256 
2257     if (nullptr != (pNode->GetSubNode(RSUP+1)))
2258     {
2259         nVariation=0;
2260         if (pNode->GetSubNode(RSUB+1))
2261             nVariation=2;
2262     }
2263     else if (nullptr != pNode->GetSubNode(RSUB+1))
2264         nVariation=1;
2265 
2266     if (nVariation!=0xff)
2267     {
2268         pS->WriteUChar( TMPL ); //Template
2269         pS->WriteUChar( 0x0F ); //selector
2270         pS->WriteUChar( nVariation );
2271         pS->WriteUChar( 0x00 ); //options
2272         pS->WriteUChar( 0x0B );
2273 
2274         if (nullptr != (pTemp = pNode->GetSubNode(RSUB+1)))
2275         {
2276             pS->WriteUChar( LINE ); //line
2277             HandleNodes(pTemp,nLevel+1);
2278             pS->WriteUChar( END ); //line
2279         }
2280         else
2281             pS->WriteUChar( LINE|0x10 );
2282         if (nullptr != (pTemp = pNode->GetSubNode(RSUP+1)))
2283         {
2284             pS->WriteUChar( LINE ); //line
2285             HandleNodes(pTemp,nLevel+1);
2286             pS->WriteUChar( END ); //line
2287         }
2288         else
2289             pS->WriteUChar( LINE|0x10 );
2290         pS->WriteUChar( END ); //line
2291     }
2292 
2293     //After subscript mathtype will keep the size of
2294     //normal text at the subscript size, sigh.
2295     pS->WriteUChar( 0x0A );
2296 }
2297 
2298 
HandleFractions(SmNode * pNode,int nLevel)2299 void MathType::HandleFractions(SmNode *pNode,int nLevel)
2300 {
2301     SmNode *pTemp;
2302     pS->WriteUChar( TMPL ); //Template
2303     pS->WriteUChar( 0x0E ); //selector
2304     pS->WriteUChar( 0x00 ); //variation
2305     pS->WriteUChar( 0x00 ); //options
2306 
2307     pS->WriteUChar( 0x0A );
2308     pS->WriteUChar( LINE ); //line
2309     if (nullptr != (pTemp = pNode->GetSubNode(0)))
2310         HandleNodes(pTemp,nLevel+1);
2311     pS->WriteUChar( END );
2312 
2313     pS->WriteUChar( 0x0A );
2314     pS->WriteUChar( LINE ); //line
2315     if (nullptr != (pTemp = pNode->GetSubNode(2)))
2316         HandleNodes(pTemp,nLevel+1);
2317     pS->WriteUChar( END );
2318 
2319     pS->WriteUChar( END );
2320 }
2321 
2322 
HandleBrace(SmNode * pNode,int nLevel)2323 void MathType::HandleBrace(SmNode *pNode,int nLevel)
2324 {
2325     SmNode *pTemp;
2326     SmNode *pLeft=pNode->GetSubNode(0);
2327     SmNode *pRight=pNode->GetSubNode(2);
2328 
2329     pS->WriteUChar( TMPL ); //Template
2330     bIsReInterpBrace=false;
2331     sal_uInt8 nBSpec=0x10;
2332     auto nLoc = pS->Tell();
2333     if (pLeft)
2334     {
2335         switch (pLeft->GetToken().eType)
2336         {
2337             case TLANGLE:
2338                 pS->WriteUChar( tmANGLE ); //selector
2339                 pS->WriteUChar( 0 ); //variation
2340                 pS->WriteUChar( 0 ); //options
2341                 break;
2342             case TLBRACE:
2343                 pS->WriteUChar( tmBRACE ); //selector
2344                 pS->WriteUChar( 0 ); //variation
2345                 pS->WriteUChar( 0 ); //options
2346                 nBSpec+=3;
2347                 break;
2348             case TLBRACKET:
2349                 pS->WriteUChar( tmBRACK ); //selector
2350                 pS->WriteUChar( 0 ); //variation
2351                 pS->WriteUChar( 0 ); //options
2352                 nBSpec+=3;
2353                 break;
2354             case TLFLOOR:
2355                 pS->WriteUChar( tmFLOOR ); //selector
2356                 pS->WriteUChar( 0 ); //variation
2357                 pS->WriteUChar( 0 ); //options
2358                 break;
2359             case TLLINE:
2360                 pS->WriteUChar( tmBAR ); //selector
2361                 pS->WriteUChar( 0 ); //variation
2362                 pS->WriteUChar( 0 ); //options
2363                 nBSpec+=3;
2364                 break;
2365             case TLDLINE:
2366                 pS->WriteUChar( tmDBAR ); //selector
2367                 pS->WriteUChar( 0 ); //variation
2368                 pS->WriteUChar( 0 ); //options
2369                 break;
2370             default:
2371                 pS->WriteUChar( tmPAREN ); //selector
2372                 pS->WriteUChar( 0 ); //variation
2373                 pS->WriteUChar( 0 ); //options
2374                 nBSpec+=3;
2375                 break;
2376         }
2377     }
2378 
2379     if (nullptr != (pTemp = pNode->GetSubNode(1)))
2380     {
2381         pS->WriteUChar( LINE ); //line
2382         HandleNodes(pTemp,nLevel+1);
2383         pS->WriteUChar( END ); //options
2384     }
2385     nSpec=nBSpec;
2386     if (pLeft)
2387         HandleNodes(pLeft,nLevel+1);
2388     if (bIsReInterpBrace)
2389     {
2390         auto nLoc2 = pS->Tell();
2391         pS->Seek(nLoc);
2392         pS->WriteUChar( 0x2D );
2393         pS->Seek(nLoc2);
2394         pS->WriteUChar( CHAR );
2395         pS->WriteUChar( 0x96 );
2396         pS->WriteUInt16( 0xEC07 );
2397         bIsReInterpBrace=false;
2398     }
2399     if (pRight)
2400         HandleNodes(pRight,nLevel+1);
2401     nSpec=0x0;
2402     pS->WriteUChar( END );
2403 }
2404 
2405 
HandleVerticalBrace(SmNode * pNode,int nLevel)2406 void MathType::HandleVerticalBrace(SmNode *pNode,int nLevel)
2407 {
2408     SmNode *pTemp;
2409     pS->WriteUChar( TMPL ); //Template
2410     if (pNode->GetToken().eType == TUNDERBRACE)
2411         pS->WriteUChar( tmLHBRACE ); //selector
2412     else
2413         pS->WriteUChar( tmUHBRACE ); //selector
2414     pS->WriteUChar( 0 ); //variation
2415     pS->WriteUChar( 0 ); //options
2416 
2417     if (nullptr != (pTemp = pNode->GetSubNode(0)))
2418     {
2419         pS->WriteUChar( LINE ); //line
2420         HandleNodes(pTemp,nLevel+1);
2421         pS->WriteUChar( END ); //options
2422     }
2423 
2424     if (nullptr != (pTemp = pNode->GetSubNode(2)))
2425     {
2426         pS->WriteUChar( LINE ); //line
2427         HandleNodes(pTemp,nLevel+1);
2428         pS->WriteUChar( END ); //options
2429     }
2430     pS->WriteUChar( END );
2431 }
2432 
HandleOperator(SmNode * pNode,int nLevel)2433 void MathType::HandleOperator(SmNode *pNode,int nLevel)
2434 {
2435     if (HandleLim(pNode,nLevel))
2436         return;
2437 
2438     sal_uInt64 nPos;
2439     sal_uInt8 nVariation;
2440 
2441     switch (pNode->GetToken().eType)
2442     {
2443         case TIINT:
2444         case TIIINT:
2445         case TLINT:
2446         case TLLINT:
2447         case TLLLINT:
2448             nVariation=HandleCScript(pNode->GetSubNode(0),
2449                 pNode->GetSubNode(1),nLevel,&nPos,false);
2450             break;
2451         default:
2452             nVariation=HandleCScript(pNode->GetSubNode(0),
2453                 pNode->GetSubNode(1),nLevel,&nPos);
2454             break;
2455     }
2456 
2457     sal_uInt8 nOldVariation=nVariation;
2458     sal_uInt8 nIntVariation=nVariation;
2459 
2460     sal_uInt64 nPos2=0;
2461     if (nVariation != 0xff)
2462     {
2463         nPos2 = pS->Tell();
2464         pS->Seek(nPos);
2465         if (nVariation == 2)
2466         {
2467             nIntVariation=0;
2468             nVariation = 1;
2469         }
2470         else if (nVariation == 0)
2471             nVariation = 1;
2472         else if (nVariation == 1)
2473             nVariation = 0;
2474     }
2475     else
2476     {
2477         nVariation = 2;
2478         nIntVariation=0;
2479     }
2480     pS->WriteUChar( TMPL );
2481     switch(pNode->GetToken().eType)
2482     {
2483     case TINT:
2484     case TINTD:
2485         if (nOldVariation != 0xff)
2486             pS->WriteUChar( 0x18 ); //selector
2487         else
2488             pS->WriteUChar( 0x15 ); //selector
2489         pS->WriteUChar( nIntVariation ); //variation
2490         break;
2491     case TIINT:
2492         if (nOldVariation != 0xff)
2493         {
2494             pS->WriteUChar( 0x19 );
2495             pS->WriteUChar( 0x01 );
2496         }
2497         else
2498         {
2499             pS->WriteUChar( 0x16 );
2500             pS->WriteUChar( 0x00 );
2501         }
2502         break;
2503     case TIIINT:
2504         if (nOldVariation != 0xff)
2505         {
2506             pS->WriteUChar( 0x1a );
2507             pS->WriteUChar( 0x01 );
2508         }
2509         else
2510         {
2511             pS->WriteUChar( 0x17 );
2512             pS->WriteUChar( 0x00 );
2513         }
2514         break;
2515     case TLINT:
2516         if (nOldVariation != 0xff)
2517         {
2518             pS->WriteUChar( 0x18 );
2519             pS->WriteUChar( 0x02 );
2520         }
2521         else
2522         {
2523             pS->WriteUChar( 0x15 );
2524             pS->WriteUChar( 0x03 );
2525         }
2526         break;
2527     case TLLINT:
2528         if (nOldVariation != 0xff)
2529         {
2530             pS->WriteUChar( 0x19 );
2531             pS->WriteUChar( 0x00 );
2532         }
2533         else
2534         {
2535             pS->WriteUChar( 0x16 );
2536             pS->WriteUChar( 0x02 );
2537         }
2538         break;
2539     case TLLLINT:
2540         if (nOldVariation != 0xff)
2541         {
2542             pS->WriteUChar( 0x1a );
2543             pS->WriteUChar( 0x00 );
2544         }
2545         else
2546         {
2547             pS->WriteUChar( 0x17 );
2548             pS->WriteUChar( 0x02 );
2549         }
2550         break;
2551     case TSUM:
2552     default:
2553         pS->WriteUChar( 0x1d );
2554         pS->WriteUChar( nVariation );
2555         break;
2556     case TPROD:
2557         pS->WriteUChar( 0x1f );
2558         pS->WriteUChar( nVariation );
2559         break;
2560     case TCOPROD:
2561         pS->WriteUChar( 0x21 );
2562         pS->WriteUChar( nVariation );
2563         break;
2564     }
2565     pS->WriteUChar( 0 ); //options
2566 
2567     if (nPos2)
2568         pS->Seek(nPos2);
2569     else
2570     {
2571         pS->WriteUChar( LINE ); //line
2572         HandleNodes(pNode->GetSubNode(1),nLevel+1);
2573         pS->WriteUChar( END ); //line
2574         pS->WriteUChar( LINE|0x10 );
2575         pS->WriteUChar( LINE|0x10 );
2576     }
2577 
2578     pS->WriteUChar( 0x0D );
2579     switch(pNode->GetToken().eType)
2580     {
2581     case TSUM:
2582     default:
2583         pS->WriteUChar( CHAR );
2584         pS->WriteUChar( 0x86 );
2585         pS->WriteUInt16( 0x2211 );
2586         break;
2587     case TPROD:
2588         pS->WriteUChar( CHAR );
2589         pS->WriteUChar( 0x86 );
2590         pS->WriteUInt16( 0x220F );
2591         break;
2592     case TCOPROD:
2593         pS->WriteUChar( CHAR );
2594         pS->WriteUChar( 0x8B );
2595         pS->WriteUInt16( 0x2210 );
2596         break;
2597     case TIIINT:
2598     case TLLLINT:
2599         pS->WriteUChar( CHAR );
2600         pS->WriteUChar( 0x86 );
2601         pS->WriteUInt16( 0x222B );
2602         [[fallthrough]];
2603     case TIINT:
2604     case TLLINT:
2605         pS->WriteUChar( CHAR );
2606         pS->WriteUChar( 0x86 );
2607         pS->WriteUInt16( 0x222B );
2608         [[fallthrough]];
2609     case TINT:
2610     case TINTD:
2611     case TLINT:
2612         pS->WriteUChar( CHAR );
2613         pS->WriteUChar( 0x86 );
2614         pS->WriteUInt16( 0x222B );
2615         break;
2616     }
2617     pS->WriteUChar( END );
2618     pS->WriteUChar( 0x0A );
2619 }
2620 
2621 
HandlePile(int & rSetAlign,int nLevel,sal_uInt8 nSelector,sal_uInt8 nVariation)2622 bool MathType::HandlePile(int &rSetAlign, int nLevel, sal_uInt8 nSelector, sal_uInt8 nVariation)
2623 {
2624     sal_uInt8 nVAlign;
2625     pS->ReadUChar( nHAlign );
2626     pS->ReadUChar( nVAlign );
2627 
2628     HandleAlign(nHAlign, rSetAlign);
2629 
2630     rRet.append(" stack {\n");
2631     bool bRet = HandleRecords( nLevel+1, nSelector, nVariation, -1, -1 );
2632     int nRemoveFrom = rRet.getLength() >= 3 ? rRet.getLength() - 3 : 0;
2633     rRet.remove(nRemoveFrom, 2);
2634     rRet.append("} ");
2635 
2636     while (rSetAlign)
2637     {
2638         rRet.append("} ");
2639         rSetAlign--;
2640     }
2641     return bRet;
2642 }
2643 
HandleMatrix(int nLevel,sal_uInt8 nSelector,sal_uInt8 nVariation)2644 bool MathType::HandleMatrix(int nLevel, sal_uInt8 nSelector, sal_uInt8 nVariation)
2645 {
2646     sal_uInt8 nH_just,nV_just,nRows,nCols,nVAlign;
2647     pS->ReadUChar( nVAlign );
2648     pS->ReadUChar( nH_just );
2649     pS->ReadUChar( nV_just );
2650     pS->ReadUChar( nRows );
2651     pS->ReadUChar( nCols );
2652     int nBytes = ((nRows+1)*2)/8;
2653     if (((nRows+1)*2)%8)
2654         nBytes++;
2655     pS->SeekRel(nBytes);
2656     nBytes = ((nCols+1)*2)/8;
2657     if (((nCols+1)*2)%8)
2658         nBytes++;
2659     pS->SeekRel(nBytes);
2660     rRet.append(" matrix {\n");
2661     bool bRet = HandleRecords( nLevel+1, nSelector, nVariation, nRows, nCols );
2662 
2663     sal_Int32 nI = rRet.lastIndexOf('#');
2664     if (nI > 0)
2665         if (rRet[nI-1] != '#')  //missing column
2666             rRet.append("{}");
2667 
2668     rRet.append("\n} ");
2669     return bRet;
2670 }
2671 
HandleTemplate(int nLevel,sal_uInt8 & rSelector,sal_uInt8 & rVariation,sal_Int32 & rLastTemplateBracket)2672 bool MathType::HandleTemplate(int nLevel, sal_uInt8 &rSelector,
2673     sal_uInt8 &rVariation, sal_Int32 &rLastTemplateBracket)
2674 {
2675     sal_uInt8 nOption; //This appears utterly unused
2676     pS->ReadUChar( rSelector );
2677     pS->ReadUChar( rVariation );
2678     pS->ReadUChar( nOption );
2679     OSL_ENSURE(rSelector < 48,"Selector out of range");
2680     if ((rSelector >= 21) && (rSelector <=26))
2681     {
2682         OSL_ENSURE(nOption < 2,"Option out of range");
2683     }
2684     else if (rSelector <= 12)
2685     {
2686         OSL_ENSURE(nOption < 3,"Option out of range");
2687     }
2688 
2689     //For the (broken) case where one subscript template ends, and there is
2690     //another one after it, mathtype handles it as if the second one was
2691     //inside the first one and renders it as sub of sub
2692     bool bRemove=false;
2693     if ( (rSelector == 0xf) && (rLastTemplateBracket != -1) )
2694     {
2695         bRemove=true;
2696         for (sal_Int32 nI = rLastTemplateBracket+1; nI < rRet.getLength(); nI++ )
2697             if (rRet[nI] != ' ')
2698             {
2699                 bRemove=false;
2700                 break;
2701             }
2702     }
2703 
2704     //suborderlist
2705     bool bRet = HandleRecords( nLevel+1, rSelector, rVariation );
2706 
2707     if (bRemove)
2708     {
2709         if (rLastTemplateBracket < rRet.getLength())
2710             rRet.remove(rLastTemplateBracket, 1);
2711         rRet.append("} ");
2712         rLastTemplateBracket = -1;
2713     }
2714     if (rSelector == 0xf)
2715         rLastTemplateBracket = rRet.lastIndexOf('}');
2716     else
2717         rLastTemplateBracket = -1;
2718 
2719     rSelector = sal::static_int_cast< sal_uInt8 >(-1);
2720     return bRet;
2721 }
2722 
HandleEmblishments()2723 void MathType::HandleEmblishments()
2724 {
2725     sal_uInt8 nEmbel;
2726     do
2727     {
2728         pS->ReadUChar( nEmbel );
2729         if (!pS->good())
2730             break;
2731         switch (nEmbel)
2732         {
2733         case 0x02:
2734             rRet.append(" dot ");
2735             break;
2736         case 0x03:
2737             rRet.append(" ddot ");
2738             break;
2739         case 0x04:
2740             rRet.append(" dddot ");
2741             break;
2742         case 0x05:
2743             if (!nPostSup)
2744             {
2745                 sPost.append(" sup {}");
2746                 nPostSup = sPost.getLength();
2747             }
2748             sPost.insert(nPostSup-1," ' ");
2749             nPostSup += 3;
2750             break;
2751         case 0x06:
2752             if (!nPostSup)
2753             {
2754                 sPost.append(" sup {}");
2755                 nPostSup = sPost.getLength();
2756             }
2757             sPost.insert(nPostSup-1," '' ");
2758             nPostSup += 4;
2759             break;
2760         case 0x07:
2761             if (!nPostlSup)
2762             {
2763                 sPost.append(" lsup {}");
2764                 nPostlSup = sPost.getLength();
2765             }
2766             sPost.insert(nPostlSup-1," ' ");
2767             nPostlSup += 3;
2768             break;
2769         case 0x08:
2770             rRet.append(" tilde ");
2771             break;
2772         case 0x09:
2773             rRet.append(" hat ");
2774             break;
2775         case 0x0b:
2776             rRet.append(" vec ");
2777             break;
2778         case 0x10:
2779             rRet.append(" overstrike ");
2780             break;
2781         case 0x11:
2782             rRet.append(" bar ");
2783             break;
2784         case 0x12:
2785             if (!nPostSup)
2786             {
2787                 sPost.append(" sup {}");
2788                 nPostSup = sPost.getLength();
2789             }
2790             sPost.insert(nPostSup-1," ''' ");
2791             nPostSup += 5;
2792             break;
2793         case 0x14:
2794             rRet.append(" breve ");
2795             break;
2796         default:
2797             OSL_ENSURE(nEmbel < 21,"Embel out of range");
2798             break;
2799         }
2800         if (nVersion < 3)
2801             break;
2802     }while (nEmbel);
2803 }
2804 
HandleSetSize()2805 void MathType::HandleSetSize()
2806 {
2807     sal_uInt8 nTemp;
2808     pS->ReadUChar( nTemp );
2809     switch (nTemp)
2810     {
2811         case 101:
2812             pS->ReadInt16( nLSize );
2813             nLSize = -nLSize;
2814             break;
2815         case 100:
2816             pS->ReadUChar( nTemp );
2817             nLSize = nTemp;
2818             pS->ReadInt16( nDSize );
2819             break;
2820         default:
2821             nLSize = nTemp;
2822             pS->ReadUChar( nTemp );
2823             nDSize = nTemp-128;
2824             break;
2825     }
2826 }
2827 
HandleChar(sal_Int32 & rTextStart,int & rSetSize,int nLevel,sal_uInt8 nTag,sal_uInt8 nSelector,sal_uInt8 nVariation,bool bSilent)2828 bool MathType::HandleChar(sal_Int32 &rTextStart, int &rSetSize, int nLevel,
2829     sal_uInt8 nTag, sal_uInt8 nSelector, sal_uInt8 nVariation, bool bSilent)
2830 {
2831     sal_Unicode nChar(0);
2832     bool bRet = true;
2833 
2834     if (xfAUTO(nTag))
2835     {
2836     //This is a candidate for function recognition, whatever
2837     //that is!
2838     }
2839 
2840     sal_uInt8 nOldTypeFace = nTypeFace;
2841     pS->ReadUChar( nTypeFace );
2842     if (nVersion < 3)
2843     {
2844         sal_uInt8 nChar8(0);
2845         pS->ReadUChar( nChar8 );
2846         nChar = nChar8;
2847     }
2848     else
2849         pS->ReadUtf16( nChar );
2850 
2851     /*
2852     bad character, old mathtype < 3 has these
2853     */
2854     if (nChar < 0x20)
2855         return bRet;
2856 
2857     if (xfEMBELL(nTag))
2858     {
2859         //A bit tricky, the character emblishments for
2860         //mathtype can all be listed after each other, in
2861         //starmath some must go before the character and some
2862         //must go after. In addition some of the emblishments
2863         //may repeated and in starmath some of these groups
2864         //must be gathered together. sPost is the portion that
2865         //follows the char and nPostSup and nPostlSup are the
2866         //indexes at which this class of emblishment is
2867         //collated together
2868         sPost = "";
2869         nPostSup = nPostlSup = 0;
2870         int nOriglen=rRet.getLength()-rTextStart;
2871         rRet.append(" {");  // #i24340# make what would be "vec {A}_n" become "{vec {A}}_n"
2872         if ((!bSilent) && (nOriglen > 1))
2873             rRet.append("\"");
2874         bRet = HandleRecords( nLevel+1, nSelector, nVariation );
2875         if (!bSilent)
2876         {
2877             if (nOriglen > 1)
2878             {
2879                 OUString aStr;
2880                 TypeFaceToString(aStr,nOldTypeFace);
2881                 aStr += "\"";
2882                 rRet.insert(std::min(rTextStart, rRet.getLength()), aStr);
2883 
2884                 aStr.clear();
2885                 TypeFaceToString(aStr,nTypeFace);
2886                 rRet.append(aStr).append("{");
2887             }
2888             else
2889                 rRet.append(" {");
2890             rTextStart = rRet.getLength();
2891         }
2892     }
2893 
2894     if (!bSilent)
2895     {
2896         sal_Int32 nOldLen = rRet.getLength();
2897         if (
2898             HandleSize(nLSize,nDSize,rSetSize) ||
2899             (nOldTypeFace != nTypeFace)
2900            )
2901         {
2902             if ((nOldLen - rTextStart) > 1)
2903             {
2904                 rRet.insert(nOldLen, "\"");
2905                 OUString aStr;
2906                 TypeFaceToString(aStr,nOldTypeFace);
2907                 aStr += "\"";
2908                 rRet.insert(rTextStart,aStr);
2909             }
2910             rTextStart = rRet.getLength();
2911         }
2912         nOldLen = rRet.getLength();
2913         if (!LookupChar(nChar,rRet,nVersion,nTypeFace))
2914         {
2915             if (nOldLen - rTextStart > 1)
2916             {
2917                 rRet.insert(nOldLen, "\"");
2918                 OUString aStr;
2919                 TypeFaceToString(aStr,nOldTypeFace);
2920                 aStr += "\"";
2921                 rRet.insert(rTextStart, aStr);
2922             }
2923             rTextStart = rRet.getLength();
2924         }
2925         lcl_PrependDummyTerm(rRet, rTextStart);
2926     }
2927 
2928     if ((xfEMBELL(nTag)) && (!bSilent))
2929     {
2930         rRet.append("}}").append(sPost);  // #i24340# make what would be "vec {A}_n" become "{vec {A}}_n"
2931         rTextStart = rRet.getLength();
2932     }
2933     return bRet;
2934 }
2935 
HandleLim(SmNode * pNode,int nLevel)2936 bool MathType::HandleLim(SmNode *pNode,int nLevel)
2937 {
2938     bool bRet=false;
2939     //Special case for the "lim" option in StarMath
2940     if ((pNode->GetToken().eType == TLIM)
2941         || (pNode->GetToken().eType == TLIMSUP)
2942         || (pNode->GetToken().eType == TLIMINF)
2943         )
2944     {
2945         if (pNode->GetSubNode(1))
2946         {
2947             sal_uInt8 nVariation2=HandleCScript(pNode->GetSubNode(0),nullptr,
2948                 nLevel);
2949 
2950             pS->WriteUChar( 0x0A );
2951             pS->WriteUChar( LINE ); //line
2952             pS->WriteUChar( CHAR|0x10 );
2953             pS->WriteUChar( 0x82 );
2954             pS->WriteUInt16( 'l' );
2955             pS->WriteUChar( CHAR|0x10 );
2956             pS->WriteUChar( 0x82 );
2957             pS->WriteUInt16( 'i' );
2958             pS->WriteUChar( CHAR|0x10 );
2959             pS->WriteUChar( 0x82 );
2960             pS->WriteUInt16( 'm' );
2961 
2962             if (pNode->GetToken().eType == TLIMSUP)
2963             {
2964                 pS->WriteUChar( CHAR ); //some space
2965                 pS->WriteUChar( 0x98 );
2966                 pS->WriteUInt16( 0xEB04 );
2967 
2968                 pS->WriteUChar( CHAR|0x10 );
2969                 pS->WriteUChar( 0x82 );
2970                 pS->WriteUInt16( 's' );
2971                 pS->WriteUChar( CHAR|0x10 );
2972                 pS->WriteUChar( 0x82 );
2973                 pS->WriteUInt16( 'u' );
2974                 pS->WriteUChar( CHAR|0x10 );
2975                 pS->WriteUChar( 0x82 );
2976                 pS->WriteUInt16( 'p' );
2977             }
2978             else if (pNode->GetToken().eType == TLIMINF)
2979             {
2980                 pS->WriteUChar( CHAR ); //some space
2981                 pS->WriteUChar( 0x98 );
2982                 pS->WriteUInt16( 0xEB04 );
2983 
2984                 pS->WriteUChar( CHAR|0x10 );
2985                 pS->WriteUChar( 0x82 );
2986                 pS->WriteUInt16( 'i' );
2987                 pS->WriteUChar( CHAR|0x10 );
2988                 pS->WriteUChar( 0x82 );
2989                 pS->WriteUInt16( 'n' );
2990                 pS->WriteUChar( CHAR|0x10 );
2991                 pS->WriteUChar( 0x82 );
2992                 pS->WriteUInt16( 'f' );
2993             }
2994 
2995 
2996             pS->WriteUChar( CHAR ); //some space
2997             pS->WriteUChar( 0x98 );
2998             pS->WriteUInt16( 0xEB04 );
2999 
3000             if (nVariation2 != 0xff)
3001             {
3002                 pS->WriteUChar( END );
3003                 pS->WriteUChar( END );
3004             }
3005             HandleNodes(pNode->GetSubNode(1),nLevel+1);
3006             bRet = true;
3007         }
3008     }
3009     return bRet;
3010 }
3011 
HandleMAlign(SmNode * pNode,int nLevel)3012 void MathType::HandleMAlign(SmNode *pNode,int nLevel)
3013 {
3014     sal_uInt8 nPushedHAlign=nHAlign;
3015     switch(pNode->GetToken().eType)
3016     {
3017         case TALIGNC:
3018             nHAlign=2;
3019             break;
3020         case TALIGNR:
3021             nHAlign=3;
3022             break;
3023         default:
3024             nHAlign=1;
3025             break;
3026     }
3027     size_t nSize = pNode->GetNumSubNodes();
3028     for (size_t i = 0; i < nSize; ++i)
3029     {
3030         if (SmNode *pTemp = pNode->GetSubNode(i))
3031             HandleNodes(pTemp,nLevel+1);
3032     }
3033     nHAlign=nPushedHAlign;
3034 }
3035 
HandleMath(SmNode * pNode)3036 void MathType::HandleMath(SmNode *pNode)
3037 {
3038     if (pNode->GetToken().eType == TMLINE)
3039     {
3040         pS->WriteUChar( END );
3041         pS->WriteUChar( LINE );
3042         bIsReInterpBrace=true;
3043         return;
3044     }
3045     SmMathSymbolNode *pTemp = static_cast<SmMathSymbolNode *>(pNode);
3046     for(sal_Int32 i=0;i<pTemp->GetText().getLength();i++)
3047     {
3048         sal_Unicode nArse = SmTextNode::ConvertSymbolToUnicode(pTemp->GetText()[i]);
3049         if ((nArse == 0x2224) || (nArse == 0x2288) || (nArse == 0x2285) ||
3050             (nArse == 0x2289))
3051         {
3052             pS->WriteUChar( CHAR|0x20 );
3053         }
3054         else if (nPendingAttributes &&
3055                 (i == ((pTemp->GetText().getLength()+1)/2)-1))
3056             {
3057                 pS->WriteUChar( 0x22 );
3058             }
3059         else
3060             pS->WriteUChar( CHAR ); //char without formula recognition
3061         //The typeface seems to be MTEXTRA for unicode characters,
3062         //though how to determine when mathtype chooses one over
3063         //the other is unknown. This should do the trick
3064         //nevertheless.
3065         sal_uInt8 nBias;
3066         if ( (nArse == 0x2213) || (nArse == 0x2218) ||
3067             (nArse == 0x210F) || (
3068                 (nArse >= 0x22EE) && (nArse <= 0x22FF)
3069             ))
3070         {
3071             nBias = 0xB; //typeface
3072         }
3073         else if ((nArse == 0x2F) || (nArse == 0x2225))
3074             nBias = 0x2; //typeface
3075         else if ((nArse > 0x2000) || (nArse == 0x00D7))
3076             nBias = 0x6; //typeface
3077         else if (nArse == 0x3d1)
3078             nBias = 0x4;
3079         else if ((nArse > 0xFF) && ((nArse < 0x393) || (nArse > 0x3c9)))
3080             nBias = 0xB; //typeface
3081         else
3082             nBias = 0x3; //typeface
3083 
3084         pS->WriteUChar( nSpec+nBias+128 ); //typeface
3085 
3086         if (nArse == 0x2224)
3087         {
3088             pS->WriteUInt16( 0x7C );
3089             pS->WriteUChar( EMBEL );
3090             pS->WriteUChar( 0x0A );
3091             pS->WriteUChar( END ); //end embel
3092             pS->WriteUChar( END ); //end embel
3093         }
3094         else if (nArse == 0x2225)
3095             pS->WriteUInt16( 0xEC09 );
3096         else if (nArse == 0xE421)
3097             pS->WriteUInt16( 0x2265 );
3098         else if (nArse == 0x230A)
3099             pS->WriteUInt16( 0xF8F0 );
3100         else if (nArse == 0x230B)
3101             pS->WriteUInt16( 0xF8FB );
3102         else if (nArse == 0xE425)
3103             pS->WriteUInt16( 0x2264 );
3104         else if (nArse == 0x226A)
3105         {
3106             pS->WriteUInt16( 0x3C );
3107             pS->WriteUChar( CHAR );
3108             pS->WriteUChar( 0x98 );
3109             pS->WriteUInt16( 0xEB01 );
3110             pS->WriteUChar( CHAR );
3111             pS->WriteUChar( 0x86 );
3112             pS->WriteUInt16( 0x3c );
3113         }
3114         else if (nArse == 0x2288)
3115         {
3116             pS->WriteUInt16( 0x2286 );
3117             pS->WriteUChar( EMBEL );
3118             pS->WriteUChar( 0x0A );
3119             pS->WriteUChar( END ); //end embel
3120             pS->WriteUChar( END ); //end embel
3121         }
3122         else if (nArse == 0x2289)
3123         {
3124             pS->WriteUInt16( 0x2287 );
3125             pS->WriteUChar( EMBEL );
3126             pS->WriteUChar( 0x0A );
3127             pS->WriteUChar( END ); //end embel
3128             pS->WriteUChar( END ); //end embel
3129         }
3130         else if (nArse == 0x2285)
3131         {
3132             pS->WriteUInt16( 0x2283 );
3133             pS->WriteUChar( EMBEL );
3134             pS->WriteUChar( 0x0A );
3135             pS->WriteUChar( END ); //end embel
3136             pS->WriteUChar( END ); //end embel
3137         }
3138         else
3139             pS->WriteUInt16( nArse );
3140     }
3141     nPendingAttributes = 0;
3142 }
3143 
HandleAttributes(SmNode * pNode,int nLevel)3144 void MathType::HandleAttributes(SmNode *pNode,int nLevel)
3145 {
3146     int nOldPending = 0;
3147     SmNode *pTemp       = nullptr;
3148     SmTextNode *pIsText = nullptr;
3149 
3150     if (nullptr != (pTemp = pNode->GetSubNode(0)))
3151     {
3152         pIsText = static_cast<SmTextNode *>(pNode->GetSubNode(1));
3153 
3154         switch (pTemp->GetToken().eType)
3155         {
3156         case TWIDEVEC:
3157             //there's just no way we can now handle any character
3158             //attributes (from mathtypes perspective) centered
3159             //over an expression but above template attributes
3160             //such as widevec and similar constructs
3161             //we have to drop them
3162             nOldPending = StartTemplate(0x2f,0x01);
3163             break;
3164         case TCHECK: //Not Exportable
3165         case TACUTE: //Not Exportable
3166         case TGRAVE: //Not Exportable
3167         case TCIRCLE: //Not Exportable
3168         case TWIDEHARPOON: //Not Exportable
3169         case TWIDETILDE: //Not Exportable
3170         case TWIDEHAT: //Not Exportable
3171             break;
3172         case TUNDERLINE:
3173             nOldPending = StartTemplate(0x10);
3174             break;
3175         case TOVERLINE: //If the next node is not text
3176                         //or text with more than one char
3177             if ((pIsText->GetToken().eType != TTEXT) ||
3178                 (pIsText->GetText().getLength() > 1))
3179                 nOldPending = StartTemplate(0x11);
3180             break;
3181         default:
3182             nPendingAttributes++;
3183             break;
3184         }
3185     }
3186 
3187     if (pIsText)
3188         HandleNodes(pIsText,nLevel+1);
3189 
3190     switch (pTemp->GetToken().eType)
3191     {
3192         case TWIDEVEC:
3193         case TUNDERLINE:
3194             EndTemplate(nOldPending);
3195             break;
3196         case TOVERLINE:
3197             if ((pIsText->GetToken().eType != TTEXT) ||
3198                 (pIsText->GetText().getLength() > 1))
3199                 EndTemplate(nOldPending);
3200             break;
3201         default:
3202             break;
3203     }
3204 
3205     //if there was no suitable place to put the attribute,
3206     //then we have to just give up on it
3207     if (nPendingAttributes)
3208         nPendingAttributes--;
3209     else
3210     {
3211         if ((nInsertion != 0) && nullptr != (pTemp = pNode->GetSubNode(0)))
3212         {
3213             auto nPos = pS->Tell();
3214             nInsertion--;
3215             pS->Seek(nInsertion);
3216             switch(pTemp->GetToken().eType)
3217             {
3218             case TACUTE: //Not Exportable
3219             case TGRAVE: //Not Exportable
3220             case TCIRCLE: //Not Exportable
3221                 break;
3222             case TCDOT:
3223                 pS->WriteUChar( 2 );
3224                 break;
3225             case TDDOT:
3226                 pS->WriteUChar( 3 );
3227                 break;
3228             case TDDDOT:
3229                 pS->WriteUChar( 4 );
3230                 break;
3231             case TTILDE:
3232                 pS->WriteUChar( 8 );
3233                 break;
3234             case THAT:
3235                 pS->WriteUChar( 9 );
3236                 break;
3237             case TVEC:
3238                 pS->WriteUChar( 11 );
3239                 break;
3240             case TOVERSTRIKE:
3241                 pS->WriteUChar( 16 );
3242                 break;
3243             case TOVERLINE:
3244                 if ((pIsText->GetToken().eType == TTEXT) &&
3245                     (pIsText->GetText().getLength() == 1))
3246                     pS->WriteUChar( 17 );
3247                 break;
3248             case TBREVE:
3249                 pS->WriteUChar( 20 );
3250                 break;
3251             case TWIDEVEC:
3252             case TWIDEHARPOON:
3253             case TUNDERLINE:
3254             case TWIDETILDE:
3255             case TWIDEHAT:
3256                 break;
3257             case TBAR:
3258                 pS->WriteUChar( 17 );
3259                 break;
3260             default:
3261                 pS->WriteUChar( 2 );
3262                 break;
3263             }
3264             pS->Seek(nPos);
3265         }
3266     }
3267 }
3268 
HandleText(SmNode * pNode)3269 void MathType::HandleText(SmNode *pNode)
3270 {
3271     SmTextNode *pTemp = static_cast<SmTextNode *>(pNode);
3272     for(sal_Int32 i=0;i<pTemp->GetText().getLength();i++)
3273     {
3274         if (nPendingAttributes &&
3275             (i == ((pTemp->GetText().getLength()+1)/2)-1))
3276         {
3277             pS->WriteUChar( 0x22 );     //char, with attributes right
3278                                 //after the character
3279         }
3280         else
3281             pS->WriteUChar( CHAR );
3282 
3283         sal_uInt8 nFace = 0x1;
3284         if (pNode->GetFont().GetItalic() == ITALIC_NORMAL)
3285             nFace = 0x3;
3286         else if (pNode->GetFont().GetWeight() == WEIGHT_BOLD)
3287             nFace = 0x7;
3288         pS->WriteUChar( nFace+128 ); //typeface
3289         sal_uInt16 nChar = pTemp->GetText()[i];
3290         pS->WriteUInt16( SmTextNode::ConvertSymbolToUnicode(nChar) );
3291 
3292         //Mathtype can only have these sort of character
3293         //attributes on a single character, starmath can put them
3294         //anywhere, when the entity involved is a text run this is
3295         //a large effort to place the character attribute on the
3296         //central mathtype character so that it does pretty much
3297         //what the user probably has in mind. The attributes
3298         //filled in here are dummy ones which are replaced in the
3299         //ATTRIBUT handler if a suitable location for the
3300         //attributes was found here. Unfortunately it is
3301         //possible for starmath to place character attributes on
3302         //entities which cannot occur in mathtype e.g. a Summation
3303         //symbol so these attributes may be lost
3304         if (nPendingAttributes &&
3305             (i == ((pTemp->GetText().getLength()+1)/2)-1))
3306         {
3307             pS->WriteUChar( EMBEL );
3308             while (nPendingAttributes)
3309             {
3310                 pS->WriteUChar( 2 );
3311                 //wedge the attributes in here and clear
3312                 //the pending stack
3313                 nPendingAttributes--;
3314             }
3315             nInsertion=pS->Tell();
3316             pS->WriteUChar( END ); //end embel
3317             pS->WriteUChar( END ); //end embel
3318         }
3319     }
3320 }
3321 
TestImportMathType(SvStream & rStream)3322 extern "C" SAL_DLLPUBLIC_EXPORT bool TestImportMathType(SvStream &rStream)
3323 {
3324     OUStringBuffer sText;
3325     MathType aEquation(sText);
3326     bool bRet = false;
3327     try
3328     {
3329         bRet = aEquation.Parse(&rStream);
3330     }
3331     catch (const std::out_of_range&)
3332     {
3333     }
3334     return bRet;
3335 }
3336 
3337 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
3338