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