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