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