Bump version to 5.0-14
[LibreOffice.git] / starmath / source / mathtype.cxx
blob09eb7e1a23d36ffb2ed26545092fc61d9d1ec359
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.push_back(12);
29 aSizeTable.push_back(8);
30 aSizeTable.push_back(6);
31 aSizeTable.push_back(24);
32 aSizeTable.push_back(10);
33 aSizeTable.push_back(12);
34 aSizeTable.push_back(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 bool MathType::LookupChar(sal_Unicode nChar,OUString &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 += OUString( nChar );
113 bRet=true;
115 break;
116 case 0x00fb:
117 if ((nVersion < 3) && (nTypeFace == 0x81))
118 nChar = 0xDF;
119 rRet += OUString( nChar );
120 bRet=true;
121 break;
122 case 'a':
123 if ((nVersion < 3) && (nTypeFace == 0x84))
124 nChar = 0x3b1;
125 rRet += OUString( nChar );
126 bRet=true;
127 break;
128 case 'b':
129 if ((nVersion < 3) && (nTypeFace == 0x84))
130 nChar = 0x3b2;
131 rRet += OUString( nChar );
132 bRet=true;
133 break;
134 case 'l':
135 if ((nVersion < 3) && (nTypeFace == 0x84))
136 nChar = 0x3bb;
137 rRet += OUString( nChar );
138 bRet=true;
139 break;
140 case 'n':
141 if ((nVersion < 3) && (nTypeFace == 0x84))
142 nChar = 0x3bd;
143 rRet += OUString( nChar );
144 bRet=true;
145 break;
146 case 'r':
147 if ((nVersion < 3) && (nTypeFace == 0x84))
148 nChar = 0x3c1;
149 rRet += OUString( nChar );
150 bRet=true;
151 break;
152 case 'D':
153 if ((nVersion < 3) && (nTypeFace == 0x84))
154 nChar = 0x394;
155 rRet += OUString( nChar );
156 bRet=true;
157 break;
158 case 0xa9:
159 if ((nVersion < 3) && (nTypeFace == 0x82))
160 nChar = '\'';
161 rRet += OUString( nChar );
162 bRet=true;
163 break;
164 case 0x00f1:
165 if ((nVersion < 3) && (nTypeFace == 0x86))
166 pC = " \\rangle ";
167 else
169 rRet += OUString( nChar );
170 bRet=true;
172 break;
173 case 0x00a3:
174 if ((nVersion < 3) && (nTypeFace == 0x86))
175 pC = " <= ";
176 else
178 rRet += OUString( nChar );
179 bRet=true;
181 break;
182 case 0x00de:
183 if ((nVersion < 3) && (nTypeFace == 0x86))
184 pC = " drarrow ";
185 else
187 rRet += OUString( nChar );
188 bRet=true;
190 break;
191 case 0x0057:
192 if ((nVersion < 3) && (nTypeFace == 0x85))
193 pC = " %OMEGA ";
194 else
196 rRet += OUString( 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 += " " + OUString( nChar ) + " ";
445 break;
446 case 0x22a5:
447 pC = " ortho ";
448 break;
449 case 0x22c5:
450 pC = " cdot ";
451 break;
452 case 0x22ee:
453 pC = " dotsvert ";
454 break;
455 case 0x22ef:
456 pC = " dotsaxis ";
457 break;
458 case 0x22f0:
459 pC = " dotsup ";
460 break;
461 case 0x22f1:
462 pC = " dotsdown ";
463 break;
464 case MS_LANGLE:
465 case MS_LMATHANGLE:
466 pC = " langle ";
467 break;
468 case MS_RANGLE:
469 case MS_RMATHANGLE:
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 += "+";
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 += "`";
507 break;
508 case 0xeb05: //large space
509 rRet += "~";
510 break;
511 case 0x3a9:
512 pC = " %OMEGA ";
513 break;
514 default:
515 rRet += OUString( nChar );
516 bRet=true;
517 break;
519 if (pC)
520 rRet += OUString::createFromAscii( pC );
521 return bRet;
524 void MathTypeFont::AppendStyleToText(OUString &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 += OUString::createFromAscii( pC );
546 void MathType::TypeFaceToString(OUString &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 tools::SvRef<SotStorageStream> xSrc = pStor->OpenSotStream(
558 OUString("Equation Native"),
559 STREAM_STD_READ | StreamMode::NOCREATE);
560 if ( (!xSrc.Is()) || (SVSTREAM_OK != xSrc->GetError()))
561 return 0;
562 pS = &xSrc;
563 pS->SetEndian( SvStreamEndian::LITTLE );
565 EQNOLEFILEHDR aHdr;
566 aHdr.Read(pS);
567 pS->ReadUChar( nVersion );
568 pS->ReadUChar( nPlatform );
569 pS->ReadUChar( nProduct );
570 pS->ReadUChar( nProdVersion );
571 pS->ReadUChar( nProdSubVersion );
573 if (nVersion > 3) // allow only supported versions of MathType to be parsed
574 return 0;
576 int nRet = HandleRecords();
577 //little crude hack to close occasionally open expressions
578 //a sophisticated system to determine what expressions are
579 //opened is required, but this is as much work as rewriting
580 //starmaths internals.
581 rRet += "{}";
583 #if OSL_DEBUG_LEVEL > 1
584 # ifdef CAOLAN
585 //sanity check
587 //sigh, theres no point! MathType (in some bizarre subvarient) pads
588 //the end of the formula with ENDs (0)'s
589 sal_uLong nEnd = pS->Tell();
590 OSL_ENSURE(nEnd == pS->Seek(STREAM_SEEK_TO_END),
591 "Possibly unfully parsed formula");
592 # endif
593 #endif
594 return nRet;
597 static void lcl_PrependDummyTerm(OUString &rRet, sal_Int32 &rTextStart)
599 if ((rTextStart < rRet.getLength()) &&
600 (rRet[rTextStart] == '=') &&
601 ((rTextStart == 0) || (rRet[ rTextStart-1 ] == '{'))
604 rRet = rRet.replaceAt(rTextStart,0," {}");
605 rTextStart+=3;
609 static void lcl_AppendDummyTerm(OUString &rRet)
611 bool bOk=false;
612 for(int nI=rRet.getLength()-1;nI >= 0; nI--)
614 sal_Int32 nIdx = sal::static_int_cast< sal_Int32 >(nI);
615 sal_Unicode nChar = rRet[nIdx];
616 if (nChar == ' ')
617 continue;
618 if (rRet[nIdx] != '{')
619 bOk=true;
620 break;
622 if (!bOk) //No term, use dummy
623 rRet += " {}";
626 void MathType::HandleNudge()
628 sal_uInt8 nXNudge;
629 pS->ReadUChar( nXNudge );
630 sal_uInt8 nYNudge;
631 pS->ReadUChar( nYNudge );
632 if (nXNudge == 128 && nYNudge == 128)
634 sal_uInt16 nXLongNudge;
635 sal_uInt16 nYLongNudge;
636 pS->ReadUInt16( nXLongNudge );
637 pS->ReadUInt16( nYLongNudge );
640 /*Fabously complicated as many tokens have to be reordered and generally
641 *moved around from mathtypes paradigm to starmaths.*/
642 int MathType::HandleRecords(int nLevel,sal_uInt8 nSelector,
643 sal_uInt8 nVariation, int nMatrixRows,int nMatrixCols)
645 sal_uInt8 nTag,nRecord;
646 sal_uInt8 nTabType,nTabStops;
647 sal_uInt16 nTabOffset;
648 int i,nRet=1,newline=0;
649 bool bSilent=false;
650 int nPart=0;
651 OUString sPush,sMainTerm;
652 int nSetSize=0,nSetAlign=0;
653 int nCurRow=0,nCurCol=0;
654 bool bOpenString=false;
655 sal_Int32 nTextStart = 0;
656 sal_Int32 nSubSupStartPos = 0;
657 sal_Int32 nLastTemplateBracket=-1;
661 nTag = 0;
662 pS->ReadUChar( nTag );
663 nRecord = nTag&0x0F;
665 /*MathType strings can of course include words which
666 *are StarMath keywords, the simplest solution is
667 to escape strings of greater than len 1 with double
668 quotes to avoid scanning the TokenTable for matches
670 Unfortunately it may turn out that the string gets
671 split during the handling of a character emblishment
672 so this special case must be handled in the
673 character handler case 2:
675 if ((nRecord == CHAR) && (!bIsSilent) && (!bOpenString))
677 bOpenString=true;
678 nTextStart = rRet.getLength();
680 else if ((nRecord != CHAR) && (bOpenString))
682 bOpenString=false;
683 if ((rRet.getLength() - nTextStart) > 1)
685 OUString aStr;
686 TypeFaceToString(aStr,nTypeFace);
687 aStr += "\"";
688 rRet = rRet.replaceAt(nTextStart,0,aStr);
689 rRet += "\"";
691 else if (nRecord == END && !rRet.isEmpty())
693 sal_Unicode cChar = 0;
694 sal_Int32 nI = rRet.getLength()-1;
695 while (nI && ((cChar = rRet[nI]) == ' '))
696 --nI;
697 if ((cChar == '=') || (cChar == '+') || (cChar == '-'))
698 rRet += "{}";
702 switch(nRecord)
704 case LINE:
706 if (xfLMOVE(nTag))
707 HandleNudge();
709 if (newline>0)
710 rRet += "\nnewline\n";
711 if (!(xfNULL(nTag)))
713 switch (nSelector)
715 case 0x0:
716 if (nVariation==0)
717 rRet += " langle ";
718 else if (nVariation==1)
719 rRet += " \\langle ";
720 break;
721 case 0x1:
722 if (nVariation==0)
723 rRet += " left (";
724 else if (nVariation==1)
725 rRet += "\\(";
726 break;
727 case 0x2:
728 if ((nVariation==0) || (nVariation==1))
729 rRet += " left lbrace ";
730 else
731 rRet += " left none ";
732 break;
733 case 0x3:
734 if (nVariation==0)
735 rRet += " left [";
736 else if (nVariation==1)
737 rRet += "\\[";
738 break;
739 case 0x8:
740 case 0xb:
741 rRet += " \\[";
742 break;
743 case 0x4:
744 if (nVariation==0)
745 rRet += " lline ";
746 else if (nVariation==1)
747 rRet += " \\lline ";
748 break;
749 case 0x5:
750 if (nVariation==0)
751 rRet += " ldline ";
752 else if (nVariation==1)
753 rRet += " \\ldline ";
754 break;
755 case 0x6:
756 if (nVariation == 0 || nVariation == 1)
757 rRet += " left lfloor ";
758 else if (nVariation==1)
759 rRet += " left none ";
760 break;
761 case 0x7:
762 if (nVariation==0)
763 rRet += " lceil ";
764 else if (nVariation==1)
765 rRet += " \\lceil ";
766 break;
767 case 0x9:
768 case 0xa:
769 rRet += " \\]";
770 break;
771 case 0xc:
772 rRet += " \\(";
773 break;
774 case 0xd:
775 if (nPart == 0)
777 if (nVariation == 0)
778 rRet += " sqrt";
779 else
781 rRet += " nroot";
782 sPush = rRet;
783 rRet.clear();
786 rRet += " {";
787 break;
788 case 0xe:
789 if (nPart == 0)
790 rRet += " { ";
793 if (nPart == 1)
794 rRet += " over ";
795 rRet += " {";
796 break;
797 case 0xf:
798 nSubSupStartPos = rRet.getLength();
799 if ((nVariation == 0) ||
800 ((nVariation == 2) && (nPart==1)))
802 lcl_AppendDummyTerm(rRet);
803 rRet += " rSup";
805 else if ((nVariation == 1) ||
806 ((nVariation == 2) && (nPart==0)))
808 lcl_AppendDummyTerm(rRet);
809 rRet += " rSub";
811 rRet += " {";
812 break;
813 case 0x10:
814 if (nVariation == 0)
815 rRet += " {underline ";
816 else if (nVariation == 1)
817 rRet += " {underline underline ";
818 rRet += " {";
819 break;
820 case 0x11:
821 if (nVariation == 0)
822 rRet += " {overline ";
823 else if (nVariation == 1)
824 rRet += " {overline overline ";
825 rRet += " {";
826 break;
827 case 0x12:
828 if (nPart == 0)
830 if (nVariation == 0)
831 rRet += " widevec ";//left arrow above
832 else if (nVariation == 1)
833 rRet += " widevec ";//left arrow below
834 rRet += " {";
836 break;
837 case 0x13:
838 if (nPart == 0)
840 if (nVariation == 0)
841 rRet += " widevec ";//right arrow above
842 else if (nVariation == 1)
843 rRet += " widevec ";//right arrow below
844 rRet += " {";
846 break;
847 case 0x14:
848 if (nPart == 0)
850 if (nVariation == 0)
851 rRet += " widevec ";//double arrow above
852 else if (nVariation == 1)
853 rRet += " widevec ";//double arrow below
854 rRet += " {";
856 break;
857 case 0x15:
858 if (nPart == 0)
860 if ((nVariation == 3) || (nVariation == 4))
861 rRet += " lInt";
862 else
863 rRet += " Int";
864 if ( (nVariation != 0) && (nVariation != 3))
866 sPush = rRet;
867 rRet.clear();
870 if (((nVariation == 1) ||
871 (nVariation == 4)) && (nPart==1))
872 rRet += " rSub";
873 else if ((nVariation == 2) && (nPart==2))
874 rRet += " rSup";
875 else if ((nVariation == 2) && (nPart==1))
876 rRet += " rSub";
877 rRet += " {";
878 break;
879 case 0x16:
880 if (nPart == 0)
882 if ((nVariation == 2) || (nVariation == 3))
883 rRet += " llInt";
884 else
885 rRet += " iInt";
886 if ( (nVariation != 0) && (nVariation != 2))
888 sPush = rRet;
889 rRet.clear();
892 if (((nVariation == 1) ||
893 (nVariation == 3)) && (nPart==1))
894 rRet += " rSub";
895 rRet += " {";
896 break;
897 case 0x17:
898 if (nPart == 0)
900 if ((nVariation == 2) || (nVariation == 3))
901 rRet += " lllInt";
902 else
903 rRet += " iiInt";
904 if ( (nVariation != 0) && (nVariation != 2))
906 sPush = rRet;
907 rRet.clear();
910 if (((nVariation == 1) ||
911 (nVariation == 3)) && (nPart==1))
912 rRet += " rSub";
913 rRet += " {";
914 break;
915 case 0x18:
916 if (nPart == 0)
918 if (nVariation == 2)
919 rRet += " lInt";
920 else
921 rRet += " Int";
922 sPush = rRet;
923 rRet.clear();
925 if (((nVariation == 1) ||
926 (nVariation == 2)) && (nPart==1))
927 rRet += " cSub";
928 else if ((nVariation == 0) && (nPart==2))
929 rRet += " cSup";
930 else if ((nVariation == 0) && (nPart==1))
931 rRet += " cSub";
932 rRet += " {";
933 break;
934 case 0x19:
935 if (nPart == 0)
937 if (nVariation == 0)
938 rRet += " llInt";
939 else
940 rRet += " iInt";
941 sPush = rRet;
942 rRet.clear();
944 if (nPart==1)
945 rRet += " cSub";
946 rRet += " {";
947 break;
948 case 0x1a:
949 if (nPart == 0)
951 if (nVariation == 0)
952 rRet += " lllInt";
953 else
954 rRet += " iiInt";
955 sPush = rRet;
956 rRet.clear();
958 if (nPart==1)
959 rRet += " cSub";
960 rRet += " {";
961 break;
962 case 0x1b:
963 case 0x1c:
964 rRet += " {";
965 break;
966 case 0x1d:
967 if (nPart == 0)
969 rRet += " Sum";
970 if (nVariation != 2)
972 sPush = rRet;
973 rRet.clear();
976 if ((nVariation == 0) && (nPart==1))
977 rRet += " cSub";
978 else if ((nVariation == 1) && (nPart==2))
979 rRet += " cSup";
980 else if ((nVariation == 1) && (nPart==1))
981 rRet += " cSub";
982 rRet += " {";
983 break;
984 case 0x1e:
985 if (nPart == 0)
987 rRet += " Sum";
988 sPush = rRet;
989 rRet.clear();
991 if ((nVariation == 0) && (nPart==1))
992 rRet += " rSub";
993 else if ((nVariation == 1) && (nPart==2))
994 rRet += " rSup";
995 else if ((nVariation == 1) && (nPart==1))
996 rRet += " rSub";
997 rRet += " {";
998 break;
999 case 0x1f:
1000 if (nPart == 0)
1002 rRet += " Prod";
1003 if (nVariation != 2)
1005 sPush = rRet;
1006 rRet.clear();
1009 if ((nVariation == 0) && (nPart==1))
1010 rRet += " cSub";
1011 else if ((nVariation == 1) && (nPart==2))
1012 rRet += " cSup";
1013 else if ((nVariation == 1) && (nPart==1))
1014 rRet += " cSub";
1015 rRet += " {";
1016 break;
1017 case 0x20:
1018 if (nPart == 0)
1020 rRet += " Prod";
1021 sPush = rRet;
1022 rRet.clear();
1024 if ((nVariation == 0) && (nPart==1))
1025 rRet += " rSub";
1026 else if ((nVariation == 1) && (nPart==2))
1027 rRet += " rSup";
1028 else if ((nVariation == 1) && (nPart==1))
1029 rRet += " rSub";
1030 rRet += " {";
1031 break;
1032 case 0x21:
1033 if (nPart == 0)
1035 rRet += " coProd";
1036 if (nVariation != 2)
1038 sPush = rRet;
1039 rRet.clear();
1042 if ((nVariation == 0) && (nPart==1))
1043 rRet += " cSub";
1044 else if ((nVariation == 1) && (nPart==2))
1045 rRet += " cSup";
1046 else if ((nVariation == 1) && (nPart==1))
1047 rRet += " cSub";
1048 rRet += " {";
1049 break;
1050 case 0x22:
1051 if (nPart == 0)
1053 rRet += " coProd";
1054 sPush = rRet;
1055 rRet.clear();
1057 if ((nVariation == 0) && (nPart==1))
1058 rRet += " rSub";
1059 else if ((nVariation == 1) && (nPart==2))
1060 rRet += " rSup";
1061 else if ((nVariation == 1) && (nPart==1))
1062 rRet += " rSub";
1063 rRet += " {";
1064 break;
1065 case 0x23:
1066 if (nPart == 0)
1068 rRet += " union"; //union
1069 if (nVariation != 2)
1071 sPush = rRet;
1072 rRet.clear();
1075 if ((nVariation == 0) && (nPart==1))
1076 rRet += " cSub";
1077 else if ((nVariation == 1) && (nPart==2))
1078 rRet += " cSup";
1079 else if ((nVariation == 1) && (nPart==1))
1080 rRet += " cSub";
1081 rRet += " {";
1082 break;
1083 case 0x24:
1084 if (nPart == 0)
1086 rRet += " union"; //union
1087 sPush = rRet;
1088 rRet.clear();
1090 if ((nVariation == 0) && (nPart==1))
1091 rRet += " rSub";
1092 else if ((nVariation == 1) && (nPart==2))
1093 rRet += " rSup";
1094 else if ((nVariation == 1) && (nPart==1))
1095 rRet += " rSub";
1096 rRet += " {";
1097 break;
1098 case 0x25:
1099 if (nPart == 0)
1101 rRet += " intersect"; //intersect
1102 if (nVariation != 2)
1104 sPush = rRet;
1105 rRet.clear();
1108 if ((nVariation == 0) && (nPart==1))
1109 rRet += " cSub";
1110 else if ((nVariation == 1) && (nPart==2))
1111 rRet += " cSup";
1112 else if ((nVariation == 1) && (nPart==1))
1113 rRet += " cSub";
1114 rRet += " {";
1115 break;
1116 case 0x26:
1117 if (nPart == 0)
1119 rRet += " intersect"; //intersect
1120 sPush = rRet;
1121 rRet.clear();
1123 if ((nVariation == 0) && (nPart==1))
1124 rRet += " rSub";
1125 else if ((nVariation == 1) && (nPart==2))
1126 rRet += " rSup";
1127 else if ((nVariation == 1) && (nPart==1))
1128 rRet += " rSub";
1129 rRet += " {";
1130 break;
1131 case 0x27:
1132 if ((nVariation == 0) && (nPart==1))
1133 rRet += " cSup";
1134 else if ((nVariation == 1) && (nPart==1))
1135 rRet += " cSub";
1136 else if ((nVariation == 2) && (nPart==1))
1137 rRet += " cSub";
1138 else if ((nVariation == 2) && (nPart==2))
1139 rRet += " cSup";
1140 rRet += " {";
1141 break;
1142 case 0x28:
1143 if (nVariation == 0)
1145 if (nPart == 0)
1147 sPush = rRet;
1148 rRet.clear();
1151 rRet += " {";
1152 if (nVariation == 0)
1154 if (nPart == 1)
1155 rRet += "alignr ";
1157 if (nPart == 0)
1158 rRet += "\\lline ";
1159 if (nVariation == 1)
1160 rRet += "overline ";
1161 break;
1162 case 0x29:
1163 rRet += " {";
1164 break;
1165 case 0x2a:
1166 if (nPart == 0)
1168 sPush = rRet;
1169 rRet.clear();
1171 if ((nVariation == 0) && (nPart==0))
1172 rRet += " rSup";
1173 else if ((nVariation == 2) && (nPart==1))
1174 rRet += " rSup";
1175 else if ((nVariation == 1) && (nPart==0))
1176 rRet += " rSub";
1177 else if ((nVariation == 2) && (nPart==0))
1178 rRet += " rSub";
1179 rRet += " {";
1180 break;
1181 case 0x2b:
1182 if (nPart == 0)
1184 sPush = rRet;
1185 rRet.clear();
1187 if ((nVariation == 0) && (nPart==0))
1188 rRet += " cSup";
1189 else if ((nVariation == 2) && (nPart==1))
1190 rRet += " cSup";
1191 else if ((nVariation == 1) && (nPart==0))
1192 rRet += " cSub";
1193 else if ((nVariation == 2) && (nPart==0))
1194 rRet += " cSub";
1195 rRet += " {";
1196 break;
1197 case 0x2c:
1198 if (nPart == 0)
1199 rRet += "\"\"";
1200 if ((nVariation == 0)
1201 || ((nVariation == 2) && (nPart==1)))
1202 rRet += " lSup";
1203 else if ((nVariation == 1)
1204 || ((nVariation == 2) && (nPart==0)))
1205 rRet += " lSub";
1206 rRet += " {";
1207 break;
1208 case 0x2d:
1209 if (nVariation==0)
1211 if (nPart == 0)
1212 rRet += " langle ";
1214 else if (nVariation==1)
1216 rRet += " \\langle ";
1217 newline--;
1219 else if (nVariation==2)
1221 rRet += " \\lline ";
1222 newline--;
1224 break;
1225 case 0x2e:
1226 if (nVariation == 0)
1227 rRet += " widevec ";//left below
1228 else if (nVariation == 1)
1229 rRet += " widevec ";//right below
1230 else if (nVariation == 2)
1231 rRet += " widevec ";//double headed below
1232 rRet += " {";
1233 break;
1234 case 0x2f:
1235 if (nVariation == 0)
1236 rRet += " widevec ";//left above
1237 else if (nVariation == 1)
1238 rRet += " widevec ";//right above
1239 else if (nVariation == 2)
1240 rRet += " widevec ";//double headed above
1241 rRet += " {";
1242 break;
1243 default:
1244 break;
1246 sal_Int16 nOldCurSize=nCurSize;
1247 sal_Int32 nSizeStartPos = rRet.getLength();
1248 HandleSize(nLSize,nDSize,nSetSize);
1249 nRet = HandleRecords(nLevel+1);
1250 while (nSetSize)
1252 bool bOk=false;
1253 sal_Int32 nI = rRet.lastIndexOf('{');
1254 if (nI != -1)
1256 for(nI=nI+1;nI<rRet.getLength();nI++)
1257 if (rRet[nI] != ' ')
1259 bOk=true;
1260 break;
1263 else
1264 bOk=true;
1266 if (bOk)
1267 rRet += "} ";
1268 else
1269 rRet = rRet.replaceAt( nSizeStartPos, rRet.getLength(), "" );
1270 nSetSize--;
1271 nCurSize=nOldCurSize;
1275 HandleMatrixSeparator(nMatrixRows,nMatrixCols,
1276 nCurCol,nCurRow);
1278 switch (nSelector)
1280 case 0x0:
1281 if (nVariation==0)
1282 rRet += " rangle ";
1283 else if (nVariation==2)
1284 rRet += " \\rangle ";
1285 break;
1286 case 0x1:
1287 if (nVariation==0)
1288 rRet += " right )";
1289 else if (nVariation==2)
1290 rRet += "\\)";
1291 break;
1292 case 0x2:
1293 if ((nVariation==0) || (nVariation==2))
1294 rRet += " right rbrace ";
1295 else
1296 rRet += " right none ";
1297 break;
1298 case 0x3:
1299 if (nVariation==0)
1300 rRet += " right ]";
1301 else if (nVariation==2)
1302 rRet += "\\]";
1303 break;
1304 case 0x4:
1305 if (nVariation==0)
1306 rRet += " rline ";
1307 else if (nVariation==2)
1308 rRet += " \\rline ";
1309 break;
1310 case 0x5:
1311 if (nVariation==0)
1312 rRet += " rdline ";
1313 else if (nVariation==2)
1314 rRet += " \\rdline ";
1315 break;
1316 case 0x6:
1317 if (nVariation == 0 || nVariation == 2)
1318 rRet += " right rfloor ";
1319 else if (nVariation==2)
1320 rRet += " right none ";
1321 break;
1322 case 0x7:
1323 if (nVariation==0)
1324 rRet += " rceil ";
1325 else if (nVariation==2)
1326 rRet += " \\rceil ";
1327 break;
1328 case 0x8:
1329 case 0xa:
1330 rRet += "\\[";
1331 break;
1332 case 0x9:
1333 case 0xc:
1334 rRet += "\\]";
1335 break;
1336 case 0xd:
1337 rRet += "} ";
1338 if (nVariation == 1)
1340 if (nPart == 0)
1342 newline--;
1343 sMainTerm = rRet;
1344 rRet.clear();
1346 else
1348 sPush += rRet;
1349 rRet = sPush;
1350 rRet += sMainTerm;
1353 else
1355 if (nPart == 0)
1356 newline--;
1358 nPart++;
1359 break;
1360 case 0xb:
1361 rRet += "\\)";
1362 break;
1363 case 0xe:
1364 rRet += "} ";
1365 if (nPart == 0)
1366 newline--;
1367 else
1368 rRet += "} ";
1369 nPart++;
1370 break;
1371 case 0xf:
1373 if ((nPart == 0) &&
1374 ((nVariation == 2) || (nVariation == 1)))
1375 newline--;
1377 bool bOk=false;
1378 sal_Int32 nI = rRet.lastIndexOf('{');
1379 if (nI != -1)
1381 for(nI=nI+1;nI<rRet.getLength();nI++)
1382 if (rRet[nI] != ' ')
1384 bOk=true;
1385 break;
1388 else
1389 bOk=true;
1391 if (bOk)
1392 rRet += "} ";
1393 else
1394 rRet = rRet.replaceAt(nSubSupStartPos, rRet.getLength(), "");
1395 nPart++;
1397 break;
1398 case 0x2c:
1399 if ((nPart == 0) &&
1400 ((nVariation == 2) || (nVariation == 1)))
1401 newline--;
1402 rRet += "} ";
1403 nPart++;
1404 break;
1405 case 0x2e:
1406 case 0x2f:
1407 rRet += "} ";
1408 break;
1409 case 0x10:
1410 case 0x11:
1411 rRet += "}} ";
1412 break;
1413 case 0x12:
1414 case 0x13:
1415 case 0x14:
1416 if (nPart == 0)
1418 newline--;
1419 rRet += "} ";
1421 nPart++;
1422 break;
1423 case 0x1b:
1424 rRet += "} ";
1425 if (nPart == 0)
1427 newline--;
1428 rRet += "overbrace";
1430 nPart++;
1431 break;
1432 case 0x1c:
1433 rRet += "} ";
1434 if (nPart == 0)
1436 newline--;
1437 rRet += "underbrace";
1439 nPart++;
1440 break;
1441 case 0x27:
1442 if (nPart==0)
1443 newline--;
1444 else if ((nPart==1) &&
1445 ((nVariation == 2) || (nVariation == 1)))
1446 newline--;
1447 rRet += "} ";
1448 nPart++;
1449 break;
1450 case 0x28:
1451 rRet += "} ";
1452 if (nVariation == 0)
1454 if (nPart == 0)
1456 sMainTerm = rRet;
1457 rRet.clear();
1459 else
1461 sPush += rRet;
1462 rRet = sPush;
1463 rRet += " over ";
1464 rRet += sMainTerm;
1467 if (nPart == 0)
1468 newline--;
1469 nPart++;
1470 break;
1471 case 0x29:
1472 rRet += "} ";
1473 if (nPart == 0)
1475 newline--;
1476 switch (nVariation)
1478 case 1:
1479 rRet += "slash";
1480 break;
1481 default:
1482 rRet += "wideslash";
1483 break;
1486 nPart++;
1487 break;
1488 case 0x1d:
1489 case 0x1e:
1490 case 0x1f:
1491 case 0x20:
1492 case 0x21:
1493 case 0x22:
1494 case 0x23:
1495 case 0x24:
1496 case 0x25:
1497 case 0x26:
1498 rRet += "} ";
1499 if (nPart == 0)
1501 if (nVariation != 2)
1503 sMainTerm = rRet;
1504 rRet.clear();
1506 newline--;
1508 else if ((nPart == 1) && (nVariation == 0))
1510 sPush += rRet;
1511 rRet = sPush;
1512 rRet += sMainTerm;
1513 newline--;
1515 else if ((nPart == 1) && (nVariation == 1))
1516 newline--;
1517 else if ((nPart == 2) && (nVariation == 1))
1519 sPush += rRet;
1520 rRet = sPush;
1521 rRet += sMainTerm;
1522 newline--;
1524 nPart++;
1525 break;
1526 case 0x15:
1527 rRet += "} ";
1528 if (nPart == 0)
1530 if ((nVariation != 0) && (nVariation != 3))
1532 sMainTerm = rRet;
1533 rRet.clear();
1535 newline--;
1537 else if ((nPart == 1) &&
1538 ((nVariation == 1) || (nVariation==4)))
1540 sPush += rRet;
1541 rRet = sPush;
1542 rRet += sMainTerm;
1543 newline--;
1545 else if ((nPart == 1) && (nVariation == 2))
1546 newline--;
1547 else if ((nPart == 2) && (nVariation == 2))
1549 sPush += rRet;
1550 rRet = sPush;
1551 rRet += sMainTerm;
1552 newline--;
1554 nPart++;
1555 break;
1556 case 0x16:
1557 case 0x17:
1558 rRet += "} ";
1559 if (nPart == 0)
1561 if ((nVariation != 0) && (nVariation != 2))
1563 sMainTerm = rRet;
1564 rRet.clear();
1566 newline--;
1568 else if ((nPart == 1) &&
1569 ((nVariation == 1) || (nVariation==3)))
1571 sPush += rRet;
1572 rRet = sPush;
1573 rRet += sMainTerm;
1574 newline--;
1576 nPart++;
1577 break;
1578 case 0x18:
1579 rRet += "} ";
1580 if (nPart == 0)
1582 sMainTerm = rRet;
1583 rRet.clear();
1584 newline--;
1586 else if ((nPart == 1) &&
1587 ((nVariation == 1) || (nVariation==2)))
1589 sPush += rRet;
1590 rRet = sPush;
1591 rRet += sMainTerm;
1592 newline--;
1594 else if ((nPart == 1) && (nVariation == 0))
1595 newline--;
1596 else if ((nPart == 2) && (nVariation == 0))
1598 sPush += rRet;
1599 rRet = sPush;
1600 rRet += sMainTerm;
1601 newline--;
1603 nPart++;
1604 break;
1605 case 0x19:
1606 case 0x1a:
1607 rRet += "} ";
1608 if (nPart == 0)
1610 sMainTerm = rRet;
1611 rRet.clear();
1612 newline--;
1614 else if (nPart == 1)
1616 sPush += rRet;
1617 rRet = sPush;
1618 rRet += sMainTerm;
1619 newline--;
1621 nPart++;
1622 break;
1623 case 0x2a:
1624 case 0x2b:
1625 rRet += "} ";
1627 if ((nPart == 0) &&
1628 ((nVariation == 0) || (nVariation == 1)))
1630 sMainTerm = rRet;
1631 rRet.clear();
1632 newline--;
1634 else if ((nPart == 0) && (nVariation == 2))
1635 newline--;
1636 else if ((nPart == 1) && (nVariation == 2))
1638 sMainTerm = rRet;
1639 rRet.clear();
1640 newline--;
1642 else if ((nPart == 2) || ((((nPart == 1) &&
1643 (nVariation == 0)) || (nVariation == 1))))
1645 sPush+=rRet;
1646 rRet = sPush;
1647 rRet += sMainTerm;
1649 nPart++;
1650 break;
1651 case 0x2d:
1652 if (nVariation==0)
1654 if (nPart == 0)
1656 newline--; //there is another term to arrive
1657 rRet += " mline ";
1659 else
1660 rRet += " rangle ";
1662 else if (nVariation==1)
1663 rRet += " \\lline ";
1664 else if (nVariation==2)
1665 rRet += " \\rangle ";
1666 nPart++;
1667 break;
1668 default:
1669 break;
1671 bSilent = true; //Skip the optional brackets and/or
1672 //symbols that follow some of these
1673 //records. Foo Data.
1675 /*In matrices and piles we cannot separate equation
1676 *lines with the newline keyword*/
1677 if (nMatrixCols==0)
1678 newline++;
1681 break;
1682 case CHAR:
1683 if (xfLMOVE(nTag))
1684 HandleNudge();
1685 nRet = HandleChar(nTextStart,nSetSize,nLevel,nTag,nSelector,
1686 nVariation,bSilent);
1687 break;
1688 case TMPL:
1689 if (xfLMOVE(nTag))
1690 HandleNudge();
1691 nRet = HandleTemplate(nLevel,nSelector,nVariation,
1692 nLastTemplateBracket);
1693 break;
1694 case PILE:
1695 if (xfLMOVE(nTag))
1696 HandleNudge();
1697 nRet = HandlePile(nSetAlign,nLevel,nSelector,nVariation);
1698 HandleMatrixSeparator(nMatrixRows,nMatrixCols,nCurCol,nCurRow);
1699 break;
1700 case MATRIX:
1701 if (xfLMOVE(nTag))
1702 HandleNudge();
1703 nRet = HandleMatrix(nLevel,nSelector,nVariation);
1704 HandleMatrixSeparator(nMatrixRows,nMatrixCols,nCurCol,nCurRow);
1705 break;
1706 case EMBEL:
1707 if (xfLMOVE(nTag))
1708 HandleNudge();
1709 HandleEmblishments();
1710 break;
1711 case RULER:
1712 pS->ReadUChar( nTabStops );
1713 for (i=0;i<nTabStops;i++)
1715 pS->ReadUChar( nTabType );
1716 pS->ReadUInt16( nTabOffset );
1718 SAL_WARN("starmath", "Not seen in the wild Equation Ruler Field");
1719 break;
1720 case FONT:
1722 MathTypeFont aFont;
1723 pS->ReadUChar( aFont.nTface );
1725 The typeface number is the negative (which makes it
1726 positive) of the typeface value (unbiased) that appears in
1727 CHAR records that might follow a given FONT record
1729 aFont.nTface = 128-aFont.nTface;
1730 pS->ReadUChar( aFont.nStyle );
1731 aUserStyles.insert(aFont);
1732 std::vector<sal_Char> aSeq;
1733 while(true)
1735 sal_Char nChar8(0);
1736 pS->ReadChar( nChar8 );
1737 if (nChar8 == 0)
1738 break;
1739 aSeq.push_back(nChar8);
1741 // Do nothing to the font name now in aSeq!?
1743 break;
1744 case SIZE:
1745 HandleSetSize();
1746 break;
1747 case 10:
1748 case 11:
1749 case 12:
1750 case 13:
1751 case 14:
1752 nLSize=nRecord-10;
1753 break;
1754 case END:
1755 default:
1756 break;
1759 while (nRecord != END && !pS->IsEof());
1760 while (nSetSize)
1762 rRet += "}";
1763 nSetSize--;
1765 return nRet;
1768 /*Simply determine if we are at the end of a record or the end of a line,
1769 *with fiddley logic to see if we are in a matrix or a pile or neither
1771 Note we cannot tell until after the event that this is the last entry
1772 of a pile, so we must strip the last separator of a pile after this
1773 is detected in the PILE handler
1775 void MathType::HandleMatrixSeparator(int nMatrixRows,int nMatrixCols,
1776 int &rCurCol,int &rCurRow)
1778 if (nMatrixRows!=0)
1780 if (rCurCol == nMatrixCols-1)
1782 if (rCurRow != nMatrixRows-1)
1783 rRet += " {} ##\n";
1784 if (nMatrixRows!=-1)
1786 rCurCol=0;
1787 rCurRow++;
1790 else
1792 rRet += " {} # ";
1793 if (nMatrixRows!=-1)
1794 rCurCol++;
1795 else
1796 rRet += "\n";
1801 /* set the alignment of the following term, but starmath currently
1802 * cannot handle vertical alignment */
1803 void MathType::HandleAlign(sal_uInt8 nHorAlign, sal_uInt8 /*nVAlign*/, int &rSetAlign)
1805 switch(nHorAlign)
1807 case 1:
1808 default:
1809 rRet += "alignl {";
1810 break;
1811 case 2:
1812 rRet += "alignc {";
1813 break;
1814 case 3:
1815 rRet += "alignr {";
1816 break;
1818 rSetAlign++;
1821 /* set size of text, complexity due to overuse of signedness as a flag
1822 * indicator by mathtype file format*/
1823 bool MathType::HandleSize(sal_Int16 nLstSize,sal_Int16 nDefSize, int &rSetSize)
1825 bool bRet=false;
1826 if (nLstSize < 0)
1828 if ((-nLstSize/32 != nDefaultSize) && (-nLstSize/32 != nCurSize))
1830 if (rSetSize)
1832 rSetSize--;
1833 rRet += "}";
1834 bRet=true;
1836 if (-nLstSize/32 != nLastSize)
1838 nLastSize = nCurSize;
1839 rRet += " size ";
1840 rRet += OUString::number(-nLstSize/32);
1841 rRet += "{";
1842 bRet=true;
1843 rSetSize++;
1845 nCurSize = -nLstSize/32;
1848 else
1850 /*sizetable should theoreticaly be filled with the default sizes
1851 *of the various font groupings matching starmaths equivalents
1852 in aTypeFaces, and a test would be done to see if the new font
1853 size would be the same as what starmath would have chosen for
1854 itself anyway in which case the size setting could be ignored*/
1855 nLstSize = aSizeTable.at(nLstSize);
1856 nLstSize = nLstSize + nDefSize;
1857 if (nLstSize != nCurSize)
1859 if (rSetSize)
1861 rSetSize--;
1862 rRet += "}";
1863 bRet=true;
1865 if (nLstSize != nLastSize)
1867 nLastSize = nCurSize;
1868 rRet += " size ";
1869 rRet += OUString::number(nLstSize);
1870 rRet += "{";
1871 bRet=true;
1872 rSetSize++;
1874 nCurSize = nLstSize;
1877 return bRet;
1880 int MathType::ConvertFromStarMath( SfxMedium& rMedium )
1882 if (!pTree)
1883 return 0;
1885 SvStream *pStream = rMedium.GetOutStream();
1886 if ( pStream )
1888 tools::SvRef<SotStorage> pStor = new SotStorage( pStream, false );
1890 SvGlobalName aGName(0x0002ce02L, 0x0000, 0x0000,0xc0,0x00,
1891 0x00,0x00,0x00,0x00,0x00,0x46 );
1892 pStor->SetClass( aGName, SotClipboardFormatId::NONE, OUString("Microsoft Equation 3.0"));
1894 static sal_uInt8 const aCompObj[] = {
1895 0x01, 0x00, 0xFE, 0xFF, 0x03, 0x0A, 0x00, 0x00,
1896 0xFF, 0xFF, 0xFF, 0xFF, 0x02, 0xCE, 0x02, 0x00,
1897 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00,
1898 0x00, 0x00, 0x00, 0x46, 0x17, 0x00, 0x00, 0x00,
1899 0x4D, 0x69, 0x63, 0x72, 0x6F, 0x73, 0x6F, 0x66,
1900 0x74, 0x20, 0x45, 0x71, 0x75, 0x61, 0x74, 0x69,
1901 0x6F, 0x6E, 0x20, 0x33, 0x2E, 0x30, 0x00, 0x0C,
1902 0x00, 0x00, 0x00, 0x44, 0x53, 0x20, 0x45, 0x71,
1903 0x75, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x00, 0x0B,
1904 0x00, 0x00, 0x00, 0x45, 0x71, 0x75, 0x61, 0x74,
1905 0x69, 0x6F, 0x6E, 0x2E, 0x33, 0x00, 0xF4, 0x39,
1906 0xB2, 0x71, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1907 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
1909 tools::SvRef<SotStorageStream> xStor( pStor->OpenSotStream(OUString("\1CompObj")));
1910 xStor->Write(aCompObj,sizeof(aCompObj));
1912 static sal_uInt8 const aOle[] = {
1913 0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00,
1914 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1915 0x00, 0x00, 0x00, 0x00
1917 tools::SvRef<SotStorageStream> xStor2( pStor->OpenSotStream(OUString("\1Ole")));
1918 xStor2->Write(aOle,sizeof(aOle));
1919 xStor.Clear();
1920 xStor2.Clear();
1922 tools::SvRef<SotStorageStream> xSrc = pStor->OpenSotStream(OUString("Equation Native"));
1923 if ( (!xSrc.Is()) || (SVSTREAM_OK != xSrc->GetError()))
1924 return 0;
1926 pS = &xSrc;
1927 pS->SetEndian( SvStreamEndian::LITTLE );
1929 pS->SeekRel(EQNOLEFILEHDR_SIZE); //Skip 28byte Header and fill it in later
1930 pS->WriteUChar( 0x03 );
1931 pS->WriteUChar( 0x01 );
1932 pS->WriteUChar( 0x01 );
1933 pS->WriteUChar( 0x03 );
1934 pS->WriteUChar( 0x00 );
1935 sal_uInt32 nSize = pS->Tell();
1936 nPendingAttributes=0;
1938 HandleNodes(pTree);
1939 pS->WriteUChar( END );
1941 nSize = pS->Tell()-nSize;
1942 pS->Seek(0);
1943 EQNOLEFILEHDR aHdr(nSize+4+1);
1944 aHdr.Write(pS);
1946 pStor->Commit();
1949 return 1;
1953 void MathType::HandleNodes(SmNode *pNode,int nLevel)
1955 switch(pNode->GetType())
1957 case NATTRIBUT:
1958 HandleAttributes(pNode,nLevel);
1959 break;
1960 case NTEXT:
1961 HandleText(pNode,nLevel);
1962 break;
1963 case NVERTICAL_BRACE:
1964 HandleVerticalBrace(pNode,nLevel);
1965 break;
1966 case NBRACE:
1967 HandleBrace(pNode,nLevel);
1968 break;
1969 case NOPER:
1970 HandleOperator(pNode,nLevel);
1971 break;
1972 case NBINVER:
1973 HandleFractions(pNode,nLevel);
1974 break;
1975 case NROOT:
1976 HandleRoot(pNode,nLevel);
1977 break;
1978 case NSPECIAL:
1980 SmTextNode *pText = static_cast<SmTextNode *>(pNode);
1981 //if the token str and the result text are the same then this
1982 //is to be seen as text, else assume it's a mathchar
1983 if (pText->GetText() == pText->GetToken().aText)
1984 HandleText(pText,nLevel);
1985 else
1986 HandleMath(pText,nLevel);
1988 break;
1989 case NMATH:
1990 case NMATHIDENT:
1991 HandleMath(pNode,nLevel);
1992 break;
1993 case NSUBSUP:
1994 HandleSubSupScript(pNode,nLevel);
1995 break;
1996 case NEXPRESSION:
1998 sal_uInt16 nSize = pNode->GetNumSubNodes();
1999 for (sal_uInt16 i = 0; i < nSize; i++)
2000 if (SmNode *pTemp = pNode->GetSubNode(i))
2001 HandleNodes(pTemp,nLevel+1);
2003 break;
2004 case NTABLE:
2005 //Root Node, PILE equivalent, i.e. vertical stack
2006 HandleTable(pNode,nLevel);
2007 break;
2008 case NMATRIX:
2009 HandleSmMatrix(static_cast<SmMatrixNode *>(pNode),nLevel);
2010 break;
2011 case NLINE:
2013 pS->WriteUChar( 0x0a );
2014 pS->WriteUChar( LINE );
2015 sal_uInt16 nSize = pNode->GetNumSubNodes();
2016 for (sal_uInt16 i = 0; i < nSize; i++)
2017 if (SmNode *pTemp = pNode->GetSubNode(i))
2018 HandleNodes(pTemp,nLevel+1);
2019 pS->WriteUChar( END );
2021 break;
2022 case NALIGN:
2023 HandleMAlign(pNode,nLevel);
2024 break;
2025 case NBLANK:
2026 pS->WriteUChar( CHAR );
2027 pS->WriteUChar( 0x98 );
2028 if (pNode->GetToken().eType == TSBLANK)
2029 pS->WriteUInt16( 0xEB04 );
2030 else
2031 pS->WriteUInt16( 0xEB05 );
2032 break;
2033 default:
2035 sal_uInt16 nSize = pNode->GetNumSubNodes();
2036 for (sal_uInt16 i = 0; i < nSize; i++)
2037 if (SmNode *pTemp = pNode->GetSubNode(i))
2038 HandleNodes(pTemp,nLevel+1);
2040 break;
2045 int MathType::StartTemplate(sal_uInt16 nSelector,sal_uInt16 nVariation)
2047 int nOldPending=nPendingAttributes;
2048 pS->WriteUChar( TMPL ); //Template
2049 pS->WriteUChar( nSelector ); //selector
2050 pS->WriteUChar( nVariation ); //variation
2051 pS->WriteUChar( 0x00 ); //options
2052 pS->WriteUChar( LINE );
2053 //theres just no way we can now handle any character
2054 //attributes (from mathtypes perspective) centered
2055 //over an expression but above template attribute
2056 //such as widevec and similar constructs
2057 //we have to drop them
2058 nPendingAttributes=0;
2059 return nOldPending;
2062 void MathType::EndTemplate(int nOldPendingAttributes)
2064 pS->WriteUChar( END ); //end line
2065 pS->WriteUChar( END ); //end template
2066 nPendingAttributes=nOldPendingAttributes;
2070 void MathType::HandleSmMatrix(SmMatrixNode *pMatrix,int nLevel)
2072 pS->WriteUChar( MATRIX );
2073 pS->WriteUChar( 0x00 ); //vAlign ?
2074 pS->WriteUChar( 0x00 ); //h_just
2075 pS->WriteUChar( 0x00 ); //v_just
2076 pS->WriteUChar( pMatrix->GetNumRows() ); //v_just
2077 pS->WriteUChar( pMatrix->GetNumCols() ); //v_just
2078 int nBytes=(pMatrix->GetNumRows()+1)*2/8;
2079 if (((pMatrix->GetNumRows()+1)*2)%8)
2080 nBytes++;
2081 for (sal_uInt16 j = 0; j < nBytes; j++)
2082 pS->WriteUChar( 0x00 ); //row_parts
2083 nBytes=(pMatrix->GetNumCols()+1)*2/8;
2084 if (((pMatrix->GetNumCols()+1)*2)%8)
2085 nBytes++;
2086 for (sal_uInt16 k = 0; k < nBytes; k++)
2087 pS->WriteUChar( 0x00 ); //col_parts
2088 sal_uInt16 nSize = pMatrix->GetNumSubNodes();
2089 for (sal_uInt16 i = 0; i < nSize; i++)
2090 if (SmNode *pTemp = pMatrix->GetSubNode(i))
2092 pS->WriteUChar( LINE ); //line
2093 HandleNodes(pTemp,nLevel+1);
2094 pS->WriteUChar( END ); //end line
2096 pS->WriteUChar( END );
2100 //Root Node, PILE equivalent, i.e. vertical stack
2101 void MathType::HandleTable(SmNode *pNode,int nLevel)
2103 sal_uInt16 nSize = pNode->GetNumSubNodes();
2104 //The root of the starmath is a table, if
2105 //we convert this them each iteration of
2106 //conversion from starmath to mathtype will
2107 //add an extra unnecessary level to the
2108 //mathtype output stack which would grow
2109 //without bound in a multi step conversion
2111 if (nLevel == 0)
2112 pS->WriteUChar( 0x0A ); //initial size
2114 if ( nLevel || (nSize >1))
2116 pS->WriteUChar( PILE );
2117 pS->WriteUChar( nHAlign ); //vAlign ?
2118 pS->WriteUChar( 0x01 ); //hAlign
2121 for (sal_uInt16 i = 0; i < nSize; i++)
2122 if (SmNode *pTemp = pNode->GetSubNode(i))
2124 pS->WriteUChar( LINE );
2125 HandleNodes(pTemp,nLevel+1);
2126 pS->WriteUChar( END );
2128 if (nLevel || (nSize>1))
2129 pS->WriteUChar( END );
2133 void MathType::HandleRoot(SmNode *pNode,int nLevel)
2135 SmNode *pTemp;
2136 pS->WriteUChar( TMPL ); //Template
2137 pS->WriteUChar( 0x0D ); //selector
2138 if (pNode->GetSubNode(0))
2139 pS->WriteUChar( 0x01 ); //variation
2140 else
2141 pS->WriteUChar( 0x00 ); //variation
2142 pS->WriteUChar( 0x00 ); //options
2144 if (NULL != (pTemp = pNode->GetSubNode(2)))
2146 pS->WriteUChar( LINE ); //line
2147 HandleNodes(pTemp,nLevel+1);
2148 pS->WriteUChar( END );
2151 if (NULL != (pTemp = pNode->GetSubNode(0)))
2153 pS->WriteUChar( LINE ); //line
2154 HandleNodes(pTemp,nLevel+1);
2155 pS->WriteUChar( END );
2157 else
2158 pS->WriteUChar( LINE|0x10 ); //dummy line
2162 pS->WriteUChar( END );
2165 sal_uInt8 MathType::HandleCScript(SmNode *pNode,SmNode *pContent,int nLevel,
2166 sal_uLong *pPos,bool bTest)
2168 sal_uInt8 nVariation2=0xff;
2170 if (bTest && pNode->GetSubNode(CSUP+1))
2172 nVariation2=0;
2173 if (pNode->GetSubNode(CSUB+1))
2174 nVariation2=2;
2176 else if (pNode->GetSubNode(CSUB+1))
2177 nVariation2=1;
2179 if (nVariation2!=0xff)
2181 if (pPos)
2182 *pPos = pS->Tell();
2183 pS->WriteUChar( TMPL ); //Template
2184 pS->WriteUChar( 0x2B ); //selector
2185 pS->WriteUChar( nVariation2 );
2186 pS->WriteUChar( 0x00 ); //options
2188 if (pContent)
2190 pS->WriteUChar( LINE ); //line
2191 HandleNodes(pContent,nLevel+1);
2192 pS->WriteUChar( END ); //line
2194 else
2195 pS->WriteUChar( LINE|0x10 );
2197 pS->WriteUChar( 0x0B );
2199 SmNode *pTemp;
2200 if (NULL != (pTemp = pNode->GetSubNode(CSUB+1)))
2202 pS->WriteUChar( LINE ); //line
2203 HandleNodes(pTemp,nLevel+1);
2204 pS->WriteUChar( END ); //line
2206 else
2207 pS->WriteUChar( LINE|0x10 );
2208 if (bTest && NULL != (pTemp = pNode->GetSubNode(CSUP+1)))
2210 pS->WriteUChar( LINE ); //line
2211 HandleNodes(pTemp,nLevel+1);
2212 pS->WriteUChar( END ); //line
2214 else
2215 pS->WriteUChar( LINE|0x10 );
2217 return nVariation2;
2223 Sub and Sup scripts and another problem area, StarMath
2224 can have all possible options used at the same time, whereas
2225 Mathtype cannot. The ordering of the nodes for each system
2226 is quite different as well leading to some complexity
2228 void MathType::HandleSubSupScript(SmNode *pNode,int nLevel)
2230 sal_uInt8 nVariation=0xff;
2231 if (pNode->GetSubNode(LSUP+1))
2233 nVariation=0;
2234 if (pNode->GetSubNode(LSUB+1))
2235 nVariation=2;
2237 else if ( NULL != pNode->GetSubNode(LSUB+1) )
2238 nVariation=1;
2240 SmNode *pTemp;
2241 if (nVariation!=0xff)
2243 pS->WriteUChar( TMPL ); //Template
2244 pS->WriteUChar( 0x2c ); //selector
2245 pS->WriteUChar( nVariation );
2246 pS->WriteUChar( 0x00 ); //options
2247 pS->WriteUChar( 0x0B );
2249 if (NULL != (pTemp = pNode->GetSubNode(LSUB+1)))
2251 pS->WriteUChar( LINE ); //line
2252 HandleNodes(pTemp,nLevel+1);
2253 pS->WriteUChar( END ); //line
2255 else
2256 pS->WriteUChar( LINE|0x10 );
2257 if (NULL != (pTemp = pNode->GetSubNode(LSUP+1)))
2259 pS->WriteUChar( LINE ); //line
2260 HandleNodes(pTemp,nLevel+1);
2261 pS->WriteUChar( END ); //line
2263 else
2264 pS->WriteUChar( LINE|0x10 );
2265 pS->WriteUChar( END );
2266 nVariation=0xff;
2270 sal_uInt8 nVariation2=HandleCScript(pNode,NULL,nLevel);
2272 if (NULL != (pTemp = pNode->GetSubNode(0)))
2274 HandleNodes(pTemp,nLevel+1);
2277 if (nVariation2 != 0xff)
2278 pS->WriteUChar( END );
2280 if (NULL != (pNode->GetSubNode(RSUP+1)))
2282 nVariation=0;
2283 if (pNode->GetSubNode(RSUB+1))
2284 nVariation=2;
2286 else if (NULL != pNode->GetSubNode(RSUB+1))
2287 nVariation=1;
2289 if (nVariation!=0xff)
2291 pS->WriteUChar( TMPL ); //Template
2292 pS->WriteUChar( 0x0F ); //selector
2293 pS->WriteUChar( nVariation );
2294 pS->WriteUChar( 0x00 ); //options
2295 pS->WriteUChar( 0x0B );
2297 if (NULL != (pTemp = pNode->GetSubNode(RSUB+1)))
2299 pS->WriteUChar( LINE ); //line
2300 HandleNodes(pTemp,nLevel+1);
2301 pS->WriteUChar( END ); //line
2303 else
2304 pS->WriteUChar( LINE|0x10 );
2305 if (NULL != (pTemp = pNode->GetSubNode(RSUP+1)))
2307 pS->WriteUChar( LINE ); //line
2308 HandleNodes(pTemp,nLevel+1);
2309 pS->WriteUChar( END ); //line
2311 else
2312 pS->WriteUChar( LINE|0x10 );
2313 pS->WriteUChar( END ); //line
2316 //After subscript mathtype will keep the size of
2317 //normal text at the subscript size, sigh.
2318 pS->WriteUChar( 0x0A );
2322 void MathType::HandleFractions(SmNode *pNode,int nLevel)
2324 SmNode *pTemp;
2325 pS->WriteUChar( TMPL ); //Template
2326 pS->WriteUChar( 0x0E ); //selector
2327 pS->WriteUChar( 0x00 ); //variation
2328 pS->WriteUChar( 0x00 ); //options
2330 pS->WriteUChar( 0x0A );
2331 pS->WriteUChar( LINE ); //line
2332 if (NULL != (pTemp = pNode->GetSubNode(0)))
2333 HandleNodes(pTemp,nLevel+1);
2334 pS->WriteUChar( END );
2336 pS->WriteUChar( 0x0A );
2337 pS->WriteUChar( LINE ); //line
2338 if (NULL != (pTemp = pNode->GetSubNode(2)))
2339 HandleNodes(pTemp,nLevel+1);
2340 pS->WriteUChar( END );
2342 pS->WriteUChar( END );
2346 void MathType::HandleBrace(SmNode *pNode,int nLevel)
2348 SmNode *pTemp;
2349 SmNode *pLeft=pNode->GetSubNode(0);
2350 SmNode *pRight=pNode->GetSubNode(2);
2352 pS->WriteUChar( TMPL ); //Template
2353 bIsReInterpBrace=false;
2354 sal_uInt8 nBSpec=0x10;
2355 sal_uLong nLoc = pS->Tell();
2356 if (pLeft)
2358 switch (pLeft->GetToken().eType)
2360 case TLANGLE:
2361 pS->WriteUChar( tmANGLE ); //selector
2362 pS->WriteUChar( 0 ); //variation
2363 pS->WriteUChar( 0 ); //options
2364 break;
2365 case TLBRACE:
2366 pS->WriteUChar( tmBRACE ); //selector
2367 pS->WriteUChar( 0 ); //variation
2368 pS->WriteUChar( 0 ); //options
2369 nBSpec+=3;
2370 break;
2371 case TLBRACKET:
2372 pS->WriteUChar( tmBRACK ); //selector
2373 pS->WriteUChar( 0 ); //variation
2374 pS->WriteUChar( 0 ); //options
2375 nBSpec+=3;
2376 break;
2377 case TLFLOOR:
2378 pS->WriteUChar( tmFLOOR ); //selector
2379 pS->WriteUChar( 0 ); //variation
2380 pS->WriteUChar( 0 ); //options
2381 break;
2382 case TLLINE:
2383 pS->WriteUChar( tmBAR ); //selector
2384 pS->WriteUChar( 0 ); //variation
2385 pS->WriteUChar( 0 ); //options
2386 nBSpec+=3;
2387 break;
2388 case TLDLINE:
2389 pS->WriteUChar( tmDBAR ); //selector
2390 pS->WriteUChar( 0 ); //variation
2391 pS->WriteUChar( 0 ); //options
2392 break;
2393 default:
2394 pS->WriteUChar( tmPAREN ); //selector
2395 pS->WriteUChar( 0 ); //variation
2396 pS->WriteUChar( 0 ); //options
2397 nBSpec+=3;
2398 break;
2402 if (NULL != (pTemp = pNode->GetSubNode(1)))
2404 pS->WriteUChar( LINE ); //line
2405 HandleNodes(pTemp,nLevel+1);
2406 pS->WriteUChar( END ); //options
2408 nSpec=nBSpec;
2409 if (pLeft)
2410 HandleNodes(pLeft,nLevel+1);
2411 if (bIsReInterpBrace)
2413 sal_uLong nLoc2 = pS->Tell();
2414 pS->Seek(nLoc);
2415 pS->WriteUChar( 0x2D );
2416 pS->Seek(nLoc2);
2417 pS->WriteUChar( CHAR );
2418 pS->WriteUChar( 0x96 );
2419 pS->WriteUInt16( 0xEC07 );
2420 bIsReInterpBrace=false;
2422 if (pRight)
2423 HandleNodes(pRight,nLevel+1);
2424 nSpec=0x0;
2425 pS->WriteUChar( END );
2429 void MathType::HandleVerticalBrace(SmNode *pNode,int nLevel)
2431 SmNode *pTemp;
2432 pS->WriteUChar( TMPL ); //Template
2433 if (pNode->GetToken().eType == TUNDERBRACE)
2434 pS->WriteUChar( tmLHBRACE ); //selector
2435 else
2436 pS->WriteUChar( tmUHBRACE ); //selector
2437 pS->WriteUChar( 0 ); //variation
2438 pS->WriteUChar( 0 ); //options
2440 if (NULL != (pTemp = pNode->GetSubNode(0)))
2442 pS->WriteUChar( LINE ); //line
2443 HandleNodes(pTemp,nLevel+1);
2444 pS->WriteUChar( END ); //options
2447 if (NULL != (pTemp = pNode->GetSubNode(2)))
2449 pS->WriteUChar( LINE ); //line
2450 HandleNodes(pTemp,nLevel+1);
2451 pS->WriteUChar( END ); //options
2453 pS->WriteUChar( END );
2456 void MathType::HandleOperator(SmNode *pNode,int nLevel)
2458 if (HandleLim(pNode,nLevel))
2459 return;
2461 sal_uLong nPos;
2462 sal_uInt8 nVariation;
2464 switch (pNode->GetToken().eType)
2466 case TIINT:
2467 case TIIINT:
2468 case TLINT:
2469 case TLLINT:
2470 case TLLLINT:
2471 nVariation=HandleCScript(pNode->GetSubNode(0),
2472 pNode->GetSubNode(1),nLevel,&nPos,false);
2473 break;
2474 default:
2475 nVariation=HandleCScript(pNode->GetSubNode(0),
2476 pNode->GetSubNode(1),nLevel,&nPos);
2477 break;
2480 sal_uInt8 nOldVariation=nVariation;
2481 sal_uInt8 nIntVariation=nVariation;
2483 sal_uLong nPos2=0;
2484 if (nVariation != 0xff)
2486 nPos2 = pS->Tell();
2487 pS->Seek(nPos);
2488 if (nVariation == 2)
2490 nIntVariation=0;
2491 nVariation = 1;
2493 else if (nVariation == 0)
2494 nVariation = 1;
2495 else if (nVariation == 1)
2496 nVariation = 0;
2498 else
2500 nVariation = 2;
2501 nIntVariation=0;
2503 pS->WriteUChar( TMPL );
2504 switch(pNode->GetToken().eType)
2506 case TINT:
2507 case TINTD:
2508 if (nOldVariation != 0xff)
2509 pS->WriteUChar( 0x18 ); //selector
2510 else
2511 pS->WriteUChar( 0x15 ); //selector
2512 pS->WriteUChar( nIntVariation ); //variation
2513 break;
2514 case TIINT:
2515 if (nOldVariation != 0xff)
2517 pS->WriteUChar( 0x19 );
2518 pS->WriteUChar( 0x01 );
2520 else
2522 pS->WriteUChar( 0x16 );
2523 pS->WriteUChar( 0x00 );
2525 break;
2526 case TIIINT:
2527 if (nOldVariation != 0xff)
2529 pS->WriteUChar( 0x1a );
2530 pS->WriteUChar( 0x01 );
2532 else
2534 pS->WriteUChar( 0x17 );
2535 pS->WriteUChar( 0x00 );
2537 break;
2538 case TLINT:
2539 if (nOldVariation != 0xff)
2541 pS->WriteUChar( 0x18 );
2542 pS->WriteUChar( 0x02 );
2544 else
2546 pS->WriteUChar( 0x15 );
2547 pS->WriteUChar( 0x03 );
2549 break;
2550 case TLLINT:
2551 if (nOldVariation != 0xff)
2553 pS->WriteUChar( 0x19 );
2554 pS->WriteUChar( 0x00 );
2556 else
2558 pS->WriteUChar( 0x16 );
2559 pS->WriteUChar( 0x02 );
2561 break;
2562 case TLLLINT:
2563 if (nOldVariation != 0xff)
2565 pS->WriteUChar( 0x1a );
2566 pS->WriteUChar( 0x00 );
2568 else
2570 pS->WriteUChar( 0x17 );
2571 pS->WriteUChar( 0x02 );
2573 break;
2574 case TSUM:
2575 default:
2576 pS->WriteUChar( 0x1d );
2577 pS->WriteUChar( nVariation );
2578 break;
2579 case TPROD:
2580 pS->WriteUChar( 0x1f );
2581 pS->WriteUChar( nVariation );
2582 break;
2583 case TCOPROD:
2584 pS->WriteUChar( 0x21 );
2585 pS->WriteUChar( nVariation );
2586 break;
2588 pS->WriteUChar( 0 ); //options
2590 if (nPos2)
2591 pS->Seek(nPos2);
2592 else
2594 pS->WriteUChar( LINE ); //line
2595 HandleNodes(pNode->GetSubNode(1),nLevel+1);
2596 pS->WriteUChar( END ); //line
2597 pS->WriteUChar( LINE|0x10 );
2598 pS->WriteUChar( LINE|0x10 );
2602 pS->WriteUChar( 0x0D );
2603 switch(pNode->GetToken().eType)
2605 case TSUM:
2606 default:
2607 pS->WriteUChar( CHAR );
2608 pS->WriteUChar( 0x86 );
2609 pS->WriteUInt16( 0x2211 );
2610 break;
2611 case TPROD:
2612 pS->WriteUChar( CHAR );
2613 pS->WriteUChar( 0x86 );
2614 pS->WriteUInt16( 0x220F );
2615 break;
2616 case TCOPROD:
2617 pS->WriteUChar( CHAR );
2618 pS->WriteUChar( 0x8B );
2619 pS->WriteUInt16( 0x2210 );
2620 break;
2621 case TIIINT:
2622 case TLLLINT:
2623 pS->WriteUChar( CHAR );
2624 pS->WriteUChar( 0x86 );
2625 pS->WriteUInt16( 0x222B );
2626 ///fall-through
2627 case TIINT:
2628 case TLLINT:
2629 pS->WriteUChar( CHAR );
2630 pS->WriteUChar( 0x86 );
2631 pS->WriteUInt16( 0x222B );
2632 ///fall-through
2633 case TINT:
2634 case TINTD:
2635 case TLINT:
2636 pS->WriteUChar( CHAR );
2637 pS->WriteUChar( 0x86 );
2638 pS->WriteUInt16( 0x222B );
2639 break;
2641 pS->WriteUChar( END );
2642 pS->WriteUChar( 0x0A );
2646 int MathType::HandlePile(int &rSetAlign,int nLevel,sal_uInt8 nSelector,
2647 sal_uInt8 nVariation)
2649 pS->ReadUChar( nHAlign );
2650 pS->ReadUChar( nVAlign );
2652 HandleAlign(nHAlign,nVAlign,rSetAlign);
2654 rRet += " stack {\n";
2655 int nRet = HandleRecords(nLevel+1,nSelector,nVariation,-1,-1);
2656 rRet = rRet.replaceAt(rRet.getLength()-3,2,"");
2657 rRet += "} ";
2659 while (rSetAlign)
2661 rRet += "} ";
2662 rSetAlign--;
2664 return nRet;
2667 int MathType::HandleMatrix(int nLevel,sal_uInt8 nSelector,
2668 sal_uInt8 nVariation)
2670 sal_uInt8 nH_just,nV_just,nRows,nCols;
2671 pS->ReadUChar( nVAlign );
2672 pS->ReadUChar( nH_just );
2673 pS->ReadUChar( nV_just );
2674 pS->ReadUChar( nRows );
2675 pS->ReadUChar( nCols );
2676 int nBytes = ((nRows+1)*2)/8;
2677 if (((nRows+1)*2)%8)
2678 nBytes++;
2679 pS->SeekRel(nBytes);
2680 nBytes = ((nCols+1)*2)/8;
2681 if (((nCols+1)*2)%8)
2682 nBytes++;
2683 pS->SeekRel(nBytes);
2684 rRet += " matrix {\n";
2685 int nRet = HandleRecords(nLevel+1,nSelector,nVariation,nRows,nCols);
2687 sal_Int32 nI = rRet.lastIndexOf('#');
2688 if (nI > 0)
2689 if (rRet[nI-1] != '#') //missing column
2690 rRet += "{}";
2692 rRet += "\n} ";
2693 return nRet;
2696 int MathType::HandleTemplate(int nLevel,sal_uInt8 &rSelector,
2697 sal_uInt8 &rVariation, sal_Int32 &rLastTemplateBracket)
2699 sal_uInt8 nOption; //This appears utterly unused
2700 pS->ReadUChar( rSelector );
2701 pS->ReadUChar( rVariation );
2702 pS->ReadUChar( nOption );
2703 OSL_ENSURE(rSelector < 48,"Selector out of range");
2704 if ((rSelector >= 21) && (rSelector <=26))
2706 OSL_ENSURE(nOption < 2,"Option out of range");
2708 else if (/*(rSelector >= 0) &&*/ (rSelector <=12))
2710 OSL_ENSURE(nOption < 3,"Option out of range");
2713 //For the (broken) case where one subscript template ends, and there is
2714 //another one after it, mathtype handles it as if the second one was
2715 //inside the first one and renders it as sub of sub
2716 bool bRemove=false;
2717 if ( (rSelector == 0xf) && (rLastTemplateBracket != -1) )
2719 bRemove=true;
2720 for (sal_Int32 nI = rLastTemplateBracket+1; nI < rRet.getLength(); nI++ )
2721 if (rRet[nI] != ' ')
2723 bRemove=false;
2724 break;
2728 //suborderlist
2729 int nRet = HandleRecords(nLevel+1,rSelector,rVariation);
2731 if (bRemove)
2733 rRet = rRet.replaceAt(rLastTemplateBracket,1,"");
2734 rRet += "} ";
2735 rLastTemplateBracket = -1;
2737 if (rSelector == 0xf)
2738 rLastTemplateBracket = rRet.lastIndexOf('}');
2739 else
2740 rLastTemplateBracket = -1;
2742 rSelector = sal::static_int_cast< sal_uInt8 >(-1);
2743 return nRet;
2746 void MathType::HandleEmblishments()
2748 sal_uInt8 nEmbel;
2751 pS->ReadUChar( nEmbel );
2752 switch (nEmbel)
2754 case 0x02:
2755 rRet += " dot ";
2756 break;
2757 case 0x03:
2758 rRet += " ddot ";
2759 break;
2760 case 0x04:
2761 rRet += " dddot ";
2762 break;
2763 case 0x05:
2764 if (!nPostSup)
2766 sPost += " sup {}";
2767 nPostSup = sPost.getLength();
2769 sPost = sPost.replaceAt(nPostSup-1,0," ' ");
2770 nPostSup += 3;
2771 break;
2772 case 0x06:
2773 if (!nPostSup)
2775 sPost += " sup {}";
2776 nPostSup = sPost.getLength();
2778 sPost = sPost.replaceAt(nPostSup-1,0," '' ");
2779 nPostSup += 4;
2780 break;
2781 case 0x07:
2782 if (!nPostlSup)
2784 sPost += " lsup {}";
2785 nPostlSup = sPost.getLength();
2787 sPost = sPost.replaceAt(nPostlSup-1,0," ' ");
2788 nPostlSup += 3;
2789 break;
2790 case 0x08:
2791 rRet += " tilde ";
2792 break;
2793 case 0x09:
2794 rRet += " hat ";
2795 break;
2796 case 0x0b:
2797 rRet += " vec ";
2798 break;
2799 case 0x10:
2800 rRet += " overstrike ";
2801 break;
2802 case 0x11:
2803 rRet += " bar ";
2804 break;
2805 case 0x12:
2806 if (!nPostSup)
2808 sPost += " sup {}";
2809 nPostSup = sPost.getLength();
2811 sPost = sPost.replaceAt(nPostSup-1,0," ''' ");
2812 nPostSup += 5;
2813 break;
2814 case 0x14:
2815 rRet += " breve ";
2816 break;
2817 default:
2818 OSL_ENSURE(nEmbel < 21,"Embel out of range");
2819 break;
2821 if (nVersion < 3)
2822 break;
2823 }while (nEmbel);
2826 void MathType::HandleSetSize()
2828 sal_uInt8 nTemp;
2829 pS->ReadUChar( nTemp );
2830 switch (nTemp)
2832 case 101:
2833 pS->ReadInt16( nLSize );
2834 nLSize = -nLSize;
2835 break;
2836 case 100:
2837 pS->ReadUChar( nTemp );
2838 nLSize = nTemp;
2839 pS->ReadInt16( nDSize );
2840 break;
2841 default:
2842 nLSize = nTemp;
2843 pS->ReadUChar( nTemp );
2844 nDSize = nTemp-128;
2845 break;
2849 int MathType::HandleChar(sal_Int32 &rTextStart,int &rSetSize,int nLevel,
2850 sal_uInt8 nTag,sal_uInt8 nSelector,sal_uInt8 nVariation, bool bSilent)
2852 sal_Unicode nChar;
2853 int nRet=1;
2855 if (xfAUTO(nTag))
2857 //This is a candidate for function recognition, whatever
2858 //that is!
2861 sal_uInt8 nOldTypeFace = nTypeFace;
2862 pS->ReadUChar( nTypeFace );
2863 if (nVersion < 3)
2865 sal_uInt8 nChar8;
2866 pS->ReadUChar( nChar8 );
2867 nChar = nChar8;
2869 else
2870 pS->ReadUInt16( nChar );
2873 bad character, old mathtype < 3 has these
2875 if (nChar < 0x20)
2876 return nRet;
2878 if (xfEMBELL(nTag))
2880 //A bit tricky, the character emblishments for
2881 //mathtype can all be listed after eachother, in
2882 //starmath some must go before the character and some
2883 //must go after. In addition some of the emblishments
2884 //may repeated and in starmath some of these groups
2885 //must be gathered together. sPost is the portion that
2886 //follows the char and nPostSup and nPostlSup are the
2887 //indexes at which this class of emblishment is
2888 //collated together
2889 sPost.clear();
2890 nPostSup = nPostlSup = 0;
2891 int nOriglen=rRet.getLength()-rTextStart;
2892 rRet += " {"; // #i24340# make what would be "vec {A}_n" become "{vec {A}}_n"
2893 if ((!bSilent) && ((nOriglen) > 1))
2894 rRet += "\"";
2895 nRet = HandleRecords(nLevel+1,nSelector,nVariation);
2896 if (!bSilent)
2898 if (nOriglen > 1)
2900 OUString aStr;
2901 TypeFaceToString(aStr,nOldTypeFace);
2902 aStr += "\"";
2903 rRet = rRet.replaceAt(rTextStart,0,aStr);
2905 aStr.clear();
2906 TypeFaceToString(aStr,nTypeFace);
2907 rRet += aStr + "{";
2909 else
2910 rRet += " {";
2911 rTextStart = rRet.getLength();
2915 if (!bSilent)
2917 sal_Int32 nOldLen = rRet.getLength();
2918 if (
2919 HandleSize(nLSize,nDSize,rSetSize) ||
2920 (nOldTypeFace != nTypeFace)
2923 if ((nOldLen - rTextStart) > 1)
2925 rRet = rRet.replaceAt(nOldLen, 0, "\"");
2926 OUString aStr;
2927 TypeFaceToString(aStr,nOldTypeFace);
2928 aStr += "\"";
2929 rRet = rRet.replaceAt(rTextStart,0,aStr);
2931 rTextStart = rRet.getLength();
2933 nOldLen = rRet.getLength();
2934 if (!LookupChar(nChar,rRet,nVersion,nTypeFace))
2936 if (nOldLen - rTextStart > 1)
2938 rRet = rRet.replaceAt(nOldLen,0,"\"");
2939 OUString aStr;
2940 TypeFaceToString(aStr,nOldTypeFace);
2941 aStr += "\"";
2942 rRet = rRet.replaceAt(rTextStart, 0, aStr);
2944 rTextStart = rRet.getLength();
2946 lcl_PrependDummyTerm(rRet, rTextStart);
2949 if ((xfEMBELL(nTag)) && (!bSilent))
2951 rRet += "}}" + sPost; // #i24340# make what would be "vec {A}_n" become "{vec {A}}_n"
2952 rTextStart = rRet.getLength();
2954 return nRet;
2957 bool MathType::HandleLim(SmNode *pNode,int nLevel)
2959 bool bRet=false;
2960 //Special case for the "lim" option in StarMath
2961 if ((pNode->GetToken().eType == TLIM)
2962 || (pNode->GetToken().eType == TLIMSUP)
2963 || (pNode->GetToken().eType == TLIMINF)
2966 if (pNode->GetSubNode(1))
2968 sal_uInt8 nVariation2=HandleCScript(pNode->GetSubNode(0),NULL,
2969 nLevel);
2971 pS->WriteUChar( 0x0A );
2972 pS->WriteUChar( LINE ); //line
2973 pS->WriteUChar( CHAR|0x10 );
2974 pS->WriteUChar( 0x82 );
2975 pS->WriteUInt16( 'l' );
2976 pS->WriteUChar( CHAR|0x10 );
2977 pS->WriteUChar( 0x82 );
2978 pS->WriteUInt16( 'i' );
2979 pS->WriteUChar( CHAR|0x10 );
2980 pS->WriteUChar( 0x82 );
2981 pS->WriteUInt16( 'm' );
2983 if (pNode->GetToken().eType == TLIMSUP)
2985 pS->WriteUChar( CHAR ); //some space
2986 pS->WriteUChar( 0x98 );
2987 pS->WriteUInt16( 0xEB04 );
2989 pS->WriteUChar( CHAR|0x10 );
2990 pS->WriteUChar( 0x82 );
2991 pS->WriteUInt16( 's' );
2992 pS->WriteUChar( CHAR|0x10 );
2993 pS->WriteUChar( 0x82 );
2994 pS->WriteUInt16( 'u' );
2995 pS->WriteUChar( CHAR|0x10 );
2996 pS->WriteUChar( 0x82 );
2997 pS->WriteUInt16( 'p' );
2999 else if (pNode->GetToken().eType == TLIMINF)
3001 pS->WriteUChar( CHAR ); //some space
3002 pS->WriteUChar( 0x98 );
3003 pS->WriteUInt16( 0xEB04 );
3005 pS->WriteUChar( CHAR|0x10 );
3006 pS->WriteUChar( 0x82 );
3007 pS->WriteUInt16( 'i' );
3008 pS->WriteUChar( CHAR|0x10 );
3009 pS->WriteUChar( 0x82 );
3010 pS->WriteUInt16( 'n' );
3011 pS->WriteUChar( CHAR|0x10 );
3012 pS->WriteUChar( 0x82 );
3013 pS->WriteUInt16( 'f' );
3017 pS->WriteUChar( CHAR ); //some space
3018 pS->WriteUChar( 0x98 );
3019 pS->WriteUInt16( 0xEB04 );
3021 if (nVariation2 != 0xff)
3023 pS->WriteUChar( END );
3024 pS->WriteUChar( END );
3026 HandleNodes(pNode->GetSubNode(1),nLevel+1);
3027 bRet = true;
3030 return bRet;
3033 void MathType::HandleMAlign(SmNode *pNode,int nLevel)
3035 sal_uInt8 nPushedHAlign=nHAlign;
3036 switch(pNode->GetToken().eType)
3038 case TALIGNC:
3039 nHAlign=2;
3040 break;
3041 case TALIGNR:
3042 nHAlign=3;
3043 break;
3044 default:
3045 nHAlign=1;
3046 break;
3048 sal_uInt16 nSize = pNode->GetNumSubNodes();
3049 for (sal_uInt16 i = 0; i < nSize; i++)
3050 if (SmNode *pTemp = pNode->GetSubNode(i))
3051 HandleNodes(pTemp,nLevel+1);
3052 nHAlign=nPushedHAlign;
3055 void MathType::HandleMath(SmNode *pNode, int /*nLevel*/)
3057 if (pNode->GetToken().eType == TMLINE)
3059 pS->WriteUChar( END );
3060 pS->WriteUChar( LINE );
3061 bIsReInterpBrace=true;
3062 return;
3064 SmMathSymbolNode *pTemp = static_cast<SmMathSymbolNode *>(pNode);
3065 for(sal_Int32 i=0;i<pTemp->GetText().getLength();i++)
3067 sal_Unicode nArse = SmTextNode::ConvertSymbolToUnicode(pTemp->GetText()[i]);
3068 if ((nArse == 0x2224) || (nArse == 0x2288) || (nArse == 0x2285) ||
3069 (nArse == 0x2289))
3071 pS->WriteUChar( CHAR|0x20 );
3073 else if ((nPendingAttributes) &&
3074 (i == ((pTemp->GetText().getLength()+1)/2)-1))
3076 pS->WriteUChar( 0x22 );
3078 else
3079 pS->WriteUChar( CHAR ); //char without formula recognition
3080 //The typeface seems to be MTEXTRA for unicode characters,
3081 //though how to determine when mathtype chooses one over
3082 //the other is unknown. This should do the trick
3083 //nevertheless.
3084 sal_uInt8 nBias;
3085 if ( (nArse == 0x2213) || (nArse == 0x2218) ||
3086 (nArse == 0x210F) || (
3087 (nArse >= 0x22EE) && (nArse <= 0x22FF)
3090 nBias = 0xB; //typeface
3092 else if ((nArse > 0x2000) || (nArse == 0x00D7))
3093 nBias = 0x6; //typeface
3094 else if (nArse == 0x3d1)
3095 nBias = 0x4;
3096 else if ((nArse > 0xFF) && ((nArse < 0x393) || (nArse > 0x3c9)))
3097 nBias = 0xB; //typeface
3098 else if ((nArse == 0x2F) || (nArse == 0x2225))
3099 nBias = 0x2; //typeface
3100 else
3101 nBias = 0x3; //typeface
3103 pS->WriteUChar( nSpec+nBias+128 ); //typeface
3105 if (nArse == 0x2224)
3107 pS->WriteUInt16( 0x7C );
3108 pS->WriteUChar( EMBEL );
3109 pS->WriteUChar( 0x0A );
3110 pS->WriteUChar( END ); //end embel
3111 pS->WriteUChar( END ); //end embel
3113 else if (nArse == 0x2225)
3114 pS->WriteUInt16( 0xEC09 );
3115 else if (nArse == 0xE421)
3116 pS->WriteUInt16( 0x2265 );
3117 else if (nArse == 0x230A)
3118 pS->WriteUInt16( 0xF8F0 );
3119 else if (nArse == 0x230B)
3120 pS->WriteUInt16( 0xF8FB );
3121 else if (nArse == 0xE425)
3122 pS->WriteUInt16( 0x2264 );
3123 else if (nArse == 0x226A)
3125 pS->WriteUInt16( 0x3C );
3126 pS->WriteUChar( CHAR );
3127 pS->WriteUChar( 0x98 );
3128 pS->WriteUInt16( 0xEB01 );
3129 pS->WriteUChar( CHAR );
3130 pS->WriteUChar( 0x86 );
3131 pS->WriteUInt16( 0x3c );
3133 else if (nArse == 0x2288)
3135 pS->WriteUInt16( 0x2286 );
3136 pS->WriteUChar( EMBEL );
3137 pS->WriteUChar( 0x0A );
3138 pS->WriteUChar( END ); //end embel
3139 pS->WriteUChar( END ); //end embel
3141 else if (nArse == 0x2289)
3143 pS->WriteUInt16( 0x2287 );
3144 pS->WriteUChar( EMBEL );
3145 pS->WriteUChar( 0x0A );
3146 pS->WriteUChar( END ); //end embel
3147 pS->WriteUChar( END ); //end embel
3149 else if (nArse == 0x2285)
3151 pS->WriteUInt16( 0x2283 );
3152 pS->WriteUChar( EMBEL );
3153 pS->WriteUChar( 0x0A );
3154 pS->WriteUChar( END ); //end embel
3155 pS->WriteUChar( END ); //end embel
3157 else
3158 pS->WriteUInt16( nArse );
3160 nPendingAttributes = 0;
3163 void MathType::HandleAttributes(SmNode *pNode,int nLevel)
3165 int nOldPending = 0;
3166 SmNode *pTemp = 0;
3167 SmTextNode *pIsText = 0;
3169 if (NULL != (pTemp = pNode->GetSubNode(0)))
3171 pIsText = static_cast<SmTextNode *>(pNode->GetSubNode(1));
3173 switch (pTemp->GetToken().eType)
3175 case TWIDEVEC:
3176 //theres just no way we can now handle any character
3177 //attributes (from mathtypes perspective) centered
3178 //over an expression but above template attributes
3179 //such as widevec and similar constructs
3180 //we have to drop them
3181 nOldPending = StartTemplate(0x2f,0x01);
3182 break;
3183 case TCHECK: //Not Exportable
3184 case TACUTE: //Not Exportable
3185 case TGRAVE: //Not Exportable
3186 case TCIRCLE: //Not Exportable
3187 case TWIDETILDE: //Not Exportable
3188 case TWIDEHAT: //Not Exportable
3189 break;
3190 case TUNDERLINE:
3191 nOldPending = StartTemplate(0x10);
3192 break;
3193 case TOVERLINE: //If the next node is not text
3194 //or text with more than one char
3195 if ((pIsText->GetToken().eType != TTEXT) ||
3196 (pIsText->GetText().getLength() > 1))
3197 nOldPending = StartTemplate(0x11);
3198 break;
3199 default:
3200 nPendingAttributes++;
3201 break;
3205 if (pIsText)
3206 HandleNodes(pIsText,nLevel+1);
3208 switch (pTemp->GetToken().eType)
3210 case TWIDEVEC:
3211 case TUNDERLINE:
3212 EndTemplate(nOldPending);
3213 break;
3214 case TOVERLINE:
3215 if ((pIsText->GetToken().eType != TTEXT) ||
3216 (pIsText->GetText().getLength() > 1))
3217 EndTemplate(nOldPending);
3218 break;
3219 default:
3220 break;
3223 //if there was no suitable place to put the attribute,
3224 //then we have to just give up on it
3225 if (nPendingAttributes)
3226 nPendingAttributes--;
3227 else
3229 if ((nInsertion != 0) && NULL != (pTemp = pNode->GetSubNode(0)))
3231 sal_uLong nPos = pS->Tell();
3232 nInsertion--;
3233 pS->Seek(nInsertion);
3234 switch(pTemp->GetToken().eType)
3236 case TACUTE: //Not Exportable
3237 case TGRAVE: //Not Exportable
3238 case TCIRCLE: //Not Exportable
3239 break;
3240 case TCDOT:
3241 pS->WriteUChar( 2 );
3242 break;
3243 case TDDOT:
3244 pS->WriteUChar( 3 );
3245 break;
3246 case TDDDOT:
3247 pS->WriteUChar( 4 );
3248 break;
3249 case TTILDE:
3250 pS->WriteUChar( 8 );
3251 break;
3252 case THAT:
3253 pS->WriteUChar( 9 );
3254 break;
3255 case TVEC:
3256 pS->WriteUChar( 11 );
3257 break;
3258 case TOVERSTRIKE:
3259 pS->WriteUChar( 16 );
3260 break;
3261 case TOVERLINE:
3262 if ((pIsText->GetToken().eType == TTEXT) &&
3263 (pIsText->GetText().getLength() == 1))
3264 pS->WriteUChar( 17 );
3265 break;
3266 case TBREVE:
3267 pS->WriteUChar( 20 );
3268 break;
3269 case TWIDEVEC:
3270 case TUNDERLINE:
3271 case TWIDETILDE:
3272 case TWIDEHAT:
3273 break;
3274 case TBAR:
3275 pS->WriteUChar( 17 );
3276 break;
3277 default:
3278 pS->WriteUChar( 2 );
3279 break;
3281 pS->Seek(nPos);
3286 void MathType::HandleText(SmNode *pNode, int /*nLevel*/)
3288 SmTextNode *pTemp = static_cast<SmTextNode *>(pNode);
3289 for(sal_Int32 i=0;i<pTemp->GetText().getLength();i++)
3291 if ((nPendingAttributes) &&
3292 (i == ((pTemp->GetText().getLength()+1)/2)-1))
3294 pS->WriteUChar( 0x22 ); //char, with attributes right
3295 //after the character
3297 else
3298 pS->WriteUChar( CHAR );
3300 sal_uInt8 nFace = 0x1;
3301 if (pNode->GetFont().GetItalic() == ITALIC_NORMAL)
3302 nFace = 0x3;
3303 else if (pNode->GetFont().GetWeight() == WEIGHT_BOLD)
3304 nFace = 0x7;
3305 pS->WriteUChar( nFace+128 ); //typeface
3306 sal_uInt16 nChar = pTemp->GetText()[i];
3307 pS->WriteUInt16( SmTextNode::ConvertSymbolToUnicode(nChar) );
3309 //Mathtype can only have these sort of character
3310 //attributes on a single character, starmath can put them
3311 //anywhere, when the entity involved is a text run this is
3312 //a large effort to place the character attribute on the
3313 //central mathtype character so that it does pretty much
3314 //what the user probably has in mind. The attributes
3315 //filled in here are dummy ones which are replaced in the
3316 //ATTRIBUT handler if a suitable location for the
3317 //attributes was found here. Unfortunately it is
3318 //possible for starmath to place character attributes on
3319 //entities which cannot occur in mathtype e.g. a Summation
3320 //symbol so these attributes may be lost
3321 if ((nPendingAttributes) &&
3322 (i == ((pTemp->GetText().getLength()+1)/2)-1))
3324 pS->WriteUChar( EMBEL );
3325 while (nPendingAttributes)
3327 pS->WriteUChar( 2 );
3328 //wedge the attributes in here and clear
3329 //the pending stack
3330 nPendingAttributes--;
3332 nInsertion=pS->Tell();
3333 pS->WriteUChar( END ); //end embel
3334 pS->WriteUChar( END ); //end embel
3339 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */