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