Version 6.4.0.3, tag libreoffice-6.4.0.3
[LibreOffice.git] / hwpfilter / source / formula.cxx
blob119bd764235530ceaa5d3afe02b0f9743e12024b
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 .
20 #include "formula.h"
21 #include "grammar.hxx"
23 #include "mzstring.h"
24 #include "nodes.h"
25 #include "mapping.h"
26 #include "hwpeq.h"
27 #include <iostream>
29 #ifndef DEBUG
31 #include "hcode.h"
33 #define rstartEl(x,y) do { if (m_rxDocumentHandler.is()) m_rxDocumentHandler->startElement(x,y); } while(false)
34 #define rendEl(x) do { if (m_rxDocumentHandler.is()) m_rxDocumentHandler->endElement(x); } while(false)
35 #define rchars(x) do { if (m_rxDocumentHandler.is()) m_rxDocumentHandler->characters(x); } while(false)
36 #define runistr(x) do { if (m_rxDocumentHandler.is()) m_rxDocumentHandler->characters(x); } while(false)
37 #define reucstr(x,y) do { if (m_rxDocumentHandler.is()) m_rxDocumentHandler->characters(OUString(x,y, RTL_TEXTENCODING_EUC_KR)); } while(false)
38 #define padd(x,y,z) mxList->addAttribute(x,y,z)
39 #else
40 static int indent = 0;
41 #define inds indent++; for(int i = 0 ; i < indent ; i++) fprintf(stderr," ")
42 #define inde for(int i = 0 ; i < indent ; i++) fprintf(stderr," "); indent--
43 #define indo indent--;
44 #endif
46 void Formula::makeMathML(Node *res)
48 Node *tmp = res;
49 if( !tmp ) return;
50 #ifdef DEBUG
51 inds;
52 fprintf(stderr,"<math:math xmlns:math=\"http://www.w3.org/1998/Math/MathML\">\n");
53 #else
54 padd("xmlns:math", "CDATA", "http://www.w3.org/1998/Math/MathML");
55 rstartEl("math:math", mxList.get());
56 mxList->clear();
57 rstartEl("math:semantics", mxList.get());
58 #endif
59 if( tmp->child )
60 makeLines( tmp->child );
62 #ifdef DEBUG
63 inds;
64 fprintf(stderr,"<math:semantics/>\n");
65 indo;
66 inde;
67 fprintf(stderr,"</math:math>\n");
68 #else
69 rendEl("math:semantics");
70 rendEl("math:math");
71 #endif
74 void Formula::makeLines(Node *res)
76 Node *tmp = res;
77 if( !tmp ) return;
79 if( tmp->child ){
80 if( tmp->child->id == ID_LINES )
81 makeLines( tmp->child );
82 else
83 makeLine( tmp->child );
85 if( tmp->next )
86 makeLine( tmp->next );
89 void Formula::makeLine(Node *res)
91 if( !res ) return;
92 #ifdef DEBUG
93 inds; fprintf(stderr,"<math:mrow>\n");
94 #else
95 rstartEl("math:mrow", mxList.get());
96 #endif
97 if( res->child )
98 makeExprList( res->child );
99 #ifdef DEBUG
100 inde; fprintf(stderr,"</math:mrow>\n");
101 #else
102 rendEl("math:mrow");
103 #endif
106 void Formula::makeExprList(Node *res)
108 if( !res ) return;
109 Node *tmp = res->child;
110 if( !tmp ) return ;
112 if( tmp->id == ID_EXPRLIST ){
113 Node *next = tmp->next;
114 makeExprList( tmp ) ;
115 if( next )
116 makeExpr( next );
118 else
119 makeExpr( tmp );
122 void Formula::makeExpr(Node *res)
124 if( !res ) return;
125 Node *tmp = res->child;
126 if( !tmp ) return;
127 switch( tmp->id ) {
128 case ID_PRIMARYEXPR:
129 if( tmp->next ){
130 #ifdef DEBUG
131 inds;
132 fprintf(stderr,"<math:mrow>\n");
133 #else
134 rstartEl("math:mrow", mxList.get());
135 #endif
138 makePrimary(tmp);
140 if( tmp->next ){
141 #ifdef DEBUG
142 inde; fprintf(stderr,"</math:mrow>\n");
143 #else
144 rendEl("math:mrow");
145 #endif
147 break;
148 case ID_SUBEXPR:
149 case ID_SUPEXPR:
150 case ID_SUBSUPEXPR:
151 makeSubSup(tmp);
152 break;
153 case ID_FRACTIONEXPR:
154 case ID_OVER:
155 makeFraction(tmp);
156 break;
157 case ID_DECORATIONEXPR:
158 makeDecoration(tmp);
159 break;
160 case ID_SQRTEXPR:
161 case ID_ROOTEXPR:
162 makeRoot(tmp);
163 break;
164 case ID_ARROWEXPR:
165 break;
166 case ID_ACCENTEXPR:
167 makeAccent(tmp);
168 break;
169 case ID_PARENTH:
170 case ID_ABS:
171 makeParenth(tmp);
172 break;
173 case ID_FENCE:
174 makeFence(tmp);
175 break;
176 case ID_BLOCK:
177 makeBlock(tmp);
178 break;
179 case ID_BEGIN:
180 case ID_END:
181 break;
185 void Formula::makeIdentifier(Node *res)
187 Node *tmp = res;
188 if( !tmp ) return;
189 if( !tmp->value ) return;
190 switch( tmp->id ){
191 case ID_CHARACTER :
192 #ifdef DEBUG
193 inds;
194 fprintf(stderr,"<math:mi>%s</math:mi>\n",tmp->value);
195 indo;
196 #else
197 rstartEl("math:mi", mxList.get());
198 rchars(OUString::createFromAscii(tmp->value));
199 rendEl("math:mi");
200 #endif
201 break;
202 case ID_STRING :
204 #ifdef DEBUG
205 #else
206 rstartEl("math:mi", mxList.get());
207 reucstr(tmp->value, strlen(tmp->value));
208 rendEl("math:mi");
209 #endif
211 break;
212 case ID_IDENTIFIER :
213 #ifdef DEBUG
214 inds;
215 fprintf(stderr,"<math:mi>%s</math:mi>\n",
216 getMathMLEntity(tmp->value).c_str());
217 indo;
218 #else
219 rstartEl("math:mi", mxList.get());
220 runistr(reinterpret_cast<sal_Unicode const *>(getMathMLEntity(tmp->value).c_str()));
221 rendEl("math:mi");
222 #endif
223 break;
224 case ID_NUMBER :
225 #ifdef DEBUG
226 inds;
227 fprintf(stderr,"<math:mn>%s</math:mn>\n",tmp->value);
228 indo;
229 #else
230 rstartEl("math:mn", mxList.get());
231 rchars(OUString::createFromAscii(tmp->value));
232 rendEl("math:mn");
233 #endif
234 break;
235 case ID_OPERATOR :
236 case ID_DELIMITER :
238 #ifdef DEBUG
239 inds; fprintf(stderr,"<math:mo>%s</math:mo>\n",tmp->value); indo;
240 #else
241 rstartEl("math:mo", mxList.get());
242 runistr(reinterpret_cast<sal_Unicode const *>(getMathMLEntity(tmp->value).c_str()));
243 rendEl("math:mo");
244 #endif
245 break;
249 void Formula::makePrimary(Node *res)
251 Node *tmp = res;
252 if( !tmp ) return ;
253 if( tmp->child ){
254 if( tmp->child->id == ID_PRIMARYEXPR ){
255 makePrimary(tmp->child);
257 else{
258 makeIdentifier(tmp->child);
261 if( tmp->next ){
262 makeIdentifier(tmp->next);
266 void Formula::makeSubSup(Node *res)
268 Node *tmp = res;
269 if( !tmp ) return;
271 #ifdef DEBUG
272 inds;
273 if( res->id == ID_SUBEXPR )
274 fprintf(stderr,"<math:msub>\n");
275 else if( res->id == ID_SUPEXPR )
276 fprintf(stderr,"<math:msup>\n");
277 else
278 fprintf(stderr,"<math:msubsup>\n");
279 #else
280 if( res->id == ID_SUBEXPR )
281 rstartEl("math:msub", mxList.get());
282 else if( res->id == ID_SUPEXPR )
283 rstartEl("math:msup", mxList.get());
284 else
285 rstartEl("math:msubsup", mxList.get());
286 #endif
288 tmp = tmp->child;
289 if( res->id == ID_SUBSUPEXPR ) {
290 makeExpr(tmp);
291 makeBlock(tmp->next);
292 makeBlock(tmp->next->next);
294 else{
295 makeExpr(tmp);
296 makeExpr(tmp->next);
299 #ifdef DEBUG
300 inde;
301 if( res->id == ID_SUBEXPR )
302 fprintf(stderr,"</math:msub>\n");
303 else if( res->id == ID_SUPEXPR )
304 fprintf(stderr,"</math:msup>\n");
305 else
306 fprintf(stderr,"</math:msubsup>\n");
307 #else
308 if( res->id == ID_SUBEXPR )
309 rendEl("math:msub");
310 else if( res->id == ID_SUPEXPR )
311 rendEl("math:msup");
312 else
313 rendEl("math:msubsup");
314 #endif
317 void Formula::makeFraction(Node *res)
319 Node *tmp = res;
320 if( !tmp ) return;
322 #ifdef DEBUG
323 inds;
324 fprintf(stderr,"<math:mfrac>\n");
325 #else
326 rstartEl("math:mfrac", mxList.get());
327 #endif
329 tmp = tmp->child;
330 #ifdef DEBUG
331 inds;
332 fprintf(stderr,"<math:mrow>\n");
333 #else
334 rstartEl("math:mrow", mxList.get());
335 #endif
337 if( res->id == ID_FRACTIONEXPR )
338 makeBlock(tmp);
339 else
340 makeExprList(tmp);
342 #ifdef DEBUG
343 inde;
344 fprintf(stderr,"</math:mrow>\n");
345 inds;
346 fprintf(stderr,"<math:mrow>\n");
347 #else
348 rendEl("math:mrow");
349 rstartEl("math:mrow", mxList.get());
350 #endif
352 if( res->id == ID_FRACTIONEXPR )
353 makeBlock(tmp->next);
354 else
355 makeExprList(tmp->next);
357 #ifdef DEBUG
358 inde;
359 fprintf(stderr,"</math:mrow>\n");
360 inde;
361 fprintf(stderr,"</math:mfrac>\n");
362 #else
363 rendEl("math:mrow");
364 rendEl("math:mfrac");
365 #endif
368 void Formula::makeDecoration(Node *res)
370 int isover = 1;
371 Node *tmp = res->child;
372 if( !tmp ) return;
373 if( !strncmp(tmp->value,"under", 5) )
374 isover = 0;
375 #ifdef DEBUG
376 inds;
377 if( isover )
378 fprintf(stderr,"<math:mover>\n");
379 else
380 fprintf(stderr,"<math:munder>\n");
381 #else
382 /* FIXME: no idea when 'accent' is true or false. */
383 if( isover ){
384 padd("accent","CDATA","true");
385 rstartEl("math:mover", mxList.get());
387 else{
388 padd("accentunder","CDATA","true");
389 rstartEl("math:munder", mxList.get());
391 mxList->clear();
392 #endif
394 makeBlock(tmp->next);
396 #ifdef DEBUG
397 inds;
398 fprintf(stderr,"<math:mo>%s</math:mo>\n",
399 getMathMLEntity(tmp->value).c_str());
400 indo;
401 #else
402 rstartEl("math:mo", mxList.get());
403 runistr(reinterpret_cast<sal_Unicode const *>(getMathMLEntity(tmp->value).c_str()));
404 rendEl("math:mo");
405 #endif
407 #ifdef DEBUG
408 inde;
409 if( isover )
410 fprintf(stderr,"</math:mover>\n");
411 else
412 fprintf(stderr,"</math:munder>\n");
413 #else
414 if( isover )
415 rendEl("math:mover");
416 else
417 rendEl("math:munder");
418 #endif
421 void Formula::makeRoot(Node *res)
423 Node *tmp = res;
424 if( !tmp ) return;
425 #ifdef DEBUG
426 inds;
427 if( tmp->id == ID_SQRTEXPR )
428 fprintf(stderr,"<math:msqrt>\n");
429 else
430 fprintf(stderr,"<math:mroot>\n");
431 #else
432 if( tmp->id == ID_SQRTEXPR )
433 rstartEl("math:msqrt", mxList.get());
434 else
435 rstartEl("math:mroot", mxList.get());
436 #endif
438 if( tmp->id == ID_SQRTEXPR ){
439 makeBlock(tmp->child);
441 else{
442 makeBracket(tmp->child);
443 makeBlock(tmp->child->next);
446 #ifdef DEBUG
447 inde;
448 if( tmp->id == ID_SQRTEXPR )
449 fprintf(stderr,"</math:msqrt>\n");
450 else
451 fprintf(stderr,"</math:mroot>\n");
452 #else
453 if( tmp->id == ID_SQRTEXPR )
454 rendEl("math:msqrt");
455 else
456 rendEl("math:mroot");
457 #endif
459 void Formula::makeAccent(Node *res)
461 makeDecoration( res );
463 void Formula::makeParenth(Node *res)
465 Node *tmp = res;
466 if( !tmp ) return;
467 #ifdef DEBUG
468 inds;
469 fprintf(stderr,"<math:mrow>\n");
470 inds;
471 if( tmp->id == ID_PARENTH ){
472 fprintf(stderr,"<math:mo>(</math:mo>\n");
474 else
475 fprintf(stderr,"<math:mo>|</math:mo>\n");
476 indo; inds;
477 fprintf(stderr,"<math:mrow>\n");
478 #else
479 rstartEl("math:mrow", mxList.get());
480 rstartEl("math:mo", mxList.get());
481 if( tmp->id == ID_PARENTH )
482 rchars("(");
483 else
484 rchars("|");
485 rendEl("math:mo");
486 rstartEl("math:mrow", mxList.get());
487 #endif
489 if( tmp->child )
490 makeExprList(tmp->child);
492 #ifdef DEBUG
493 inde;
494 fprintf(stderr,"</math:mrow>\n");
495 inds;
496 if( tmp->id == ID_PARENTH )
497 fprintf(stderr,"<math:mo>)</math:mo>\n");
498 else
499 fprintf(stderr,"<math:mo>|</math:mo>\n");
500 indo;
501 inde;
502 fprintf(stderr,"</math:mrow>\n");
503 #else
504 rendEl("math:mrow");
505 rstartEl("math:mo", mxList.get());
506 if( tmp->id == ID_PARENTH )
507 rchars(")");
508 else
509 rchars("|");
510 rendEl("math:mo");
511 rendEl("math:mrow");
512 #endif
515 void Formula::makeFence(Node *res)
517 Node *tmp = res->child;
518 #ifdef DEBUG
519 inds;
520 fprintf(stderr,"<math:mfenced open=\"%s\" close=\"%s\">\n",
521 getMathMLEntity(tmp->value).c_str(),
522 getMathMLEntity(tmp->next->next->value).c_str());
523 #else
524 padd("open", "CDATA",
525 OUString(reinterpret_cast<sal_Unicode const *>(getMathMLEntity(tmp->value).c_str())));
526 padd("close", "CDATA",
527 OUString(reinterpret_cast<sal_Unicode const *>(getMathMLEntity(tmp->next->next->value).c_str())));
528 rstartEl("math:mfenced", mxList.get());
529 mxList->clear();
530 #endif
532 makeExprList(tmp->next);
534 #ifdef DEBUG
535 inde;
536 fprintf(stderr,"</math:mfenced>\n");
537 #else
538 rendEl("math:mfenced");
539 #endif
542 void Formula::makeBracket(Node *res)
544 makeBlock(res);
547 void Formula::makeBlock(Node *res)
549 #ifdef DEBUG
550 inds;
551 fprintf(stderr,"<math:mrow>\n");
552 #else
553 rstartEl("math:mrow", mxList.get());
554 #endif
556 if( res->child )
557 makeExprList(res->child);
559 #ifdef DEBUG
560 inde;
561 fprintf(stderr,"</math:mrow>\n");
562 #else
563 rendEl("math:mrow");
564 #endif
567 void Formula::parse()
569 Node *res = nullptr;
570 if( !eq ) return;
572 MzString a;
573 // fprintf(stderr,"\n\n[BEFORE]\n[%s]\n",eq);
574 eq2latex(a,eq);
576 int idx=a.find(sal::static_int_cast<char>(0xff));
577 while(idx){
578 //printf("idx = [%d]\n",idx);
579 a.replace(idx,0x20);
580 if((idx = a.find(sal::static_int_cast<char>(0xff),idx+1)) < 0)
581 break;
584 char *buf = static_cast<char *>(malloc(a.length()+1));
585 bool bStart = false;
586 int i, j;
587 for( i = 0, j=0 ; i < a.length() ; i++){ // rtrim and ltrim 32 10 13
588 if( bStart ){
589 buf[j++] = a[i];
591 else{
592 if( a[i] != 32 && a[i] != 10 && a[i] != 13){
593 bStart = true;
594 buf[j++] = a[i];
598 buf[j] = 0;
599 for( i = j-1 ; i >= 0 ; i++ ){
600 if( buf[i] == 32 || buf[i] == 10 || buf[i] == 13 ){
601 buf[i] = 0;
603 else
604 break;
606 // fprintf(stderr,"\n\n[RESULT]\n[%s]\n",a.c_str());
607 if( buf[0] != '\0' )
608 res = mainParse( a.c_str() );
609 else
610 res = nullptr;
611 free(buf);
613 if( res ){
614 makeMathML( res );
616 nodelist.clear();
619 void Formula::trim()
621 int len = strlen(eq);
622 char *buf = static_cast<char *>(malloc(len+1));
623 bool bStart = false;
624 int i, j;
625 for( i = 0, j=0 ; i < len ; i++){ // rtrim and ltrim 32 10 13
626 if( bStart ){
627 buf[j++] = eq[i];
629 else{
630 if( eq[i] != 32 && eq[i] != 10 && eq[i] != 13){
631 bStart = true;
632 buf[j++] = eq[i];
636 buf[j] = 0;
637 for( i = j-1 ; i >= 0 ; i++ ){
638 if( buf[i] == 32 || buf[i] == 10 || buf[i] == 13 ){
639 buf[i] = 0;
641 else
642 break;
644 if( buf[0] != '\0' )
645 strcpy(eq, buf);
646 else
647 eq = nullptr;
648 free(buf);
651 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */