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