    /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
    /*
     * This file is part of the LibreOffice project.
     *
     * This Source Code Form is subject to the terms of the Mozilla Public
     * License, v. 2.0. If a copy of the MPL was not distributed with this
     * file, You can obtain one at http://mozilla.org/MPL/2.0/.
     *
     * This file incorporates work covered by the following license notice:
     *
     *   Licensed to the Apache Software Foundation (ASF) under one or more
     *   contributor license agreements. See the NOTICE file distributed
     *   with this work for additional information regarding copyright
     *   ownership. The ASF licenses this file to you under the Apache
     *   License, Version 2.0 (the "License"); you may not use this file
     *   except in compliance with the License. You may obtain a copy of
     *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
     */

    #include "formula.h"
    #include "grammar.hxx"

    #include "mzstring.h"
    #include "nodes.h"
    #include "mapping.h"
    #include "hwpeq.h"
    #include <iostream>

    #ifndef DEBUG

    #include "hcode.h"

    #define rstartEl(x,y) do { if (m_rxDocumentHandler.is()) m_rxDocumentHandler->startElement(x,y); } while(false)
    #define rendEl(x) do { if (m_rxDocumentHandler.is()) m_rxDocumentHandler->endElement(x); } while(false)
    #define rchars(x) do { if (m_rxDocumentHandler.is()) m_rxDocumentHandler->characters(x); } while(false)
    #define runistr(x) do { if (m_rxDocumentHandler.is()) m_rxDocumentHandler->characters(x); } while(false)
    #define reucstr(x,y) do { if (m_rxDocumentHandler.is()) m_rxDocumentHandler->characters(OUString(x,y, RTL_TEXTENCODING_EUC_KR)); } while(false)
    #define padd(x,y,z)  mxList->addAttribute(x,y,z)
    #else
    static int indent = 0;
    #define inds indent++; for(int i = 0 ; i < indent ; i++) fprintf(stderr," ")
    #define inde for(int i = 0 ; i < indent ; i++) fprintf(stderr," "); indent--
    #define indo indent--;
    #endif

    void Formula::makeMathML(Node *res)
    {
         Node *tmp = res;
         if( !tmp ) return;
    #ifdef DEBUG
         inds;
         fprintf(stderr,"<math:math xmlns:math=\"http://www.w3.org/1998/Math/MathML\">\n");
    #else
         padd("xmlns:math", "CDATA", "http://www.w3.org/1998/Math/MathML");
         rstartEl("math:math", mxList.get());
         mxList->clear();
         rstartEl("math:semantics", mxList.get());
    #endif
         if( tmp->child )
              makeLines( tmp->child );

    #ifdef DEBUG
         inds;
         fprintf(stderr,"<math:semantics/>\n");
         indo;
         inde;
         fprintf(stderr,"</math:math>\n");
    #else
         rendEl("math:semantics");
         rendEl("math:math");
    #endif
    }

    void Formula::makeLines(Node *res)
    {
         Node *tmp = res;
         if( !tmp ) return;

         if( tmp->child ){
              if( tmp->child->id == ID_LINES )
                    makeLines( tmp->child );
              else
                    makeLine( tmp->child );
         }
         if( tmp->next )
              makeLine( tmp->next );
    }

    void Formula::makeLine(Node *res)
    {
      if( !res ) return;
    #ifdef DEBUG
         inds; fprintf(stderr,"<math:mrow>\n");
    #else
         rstartEl("math:mrow", mxList.get());
    #endif
         if( res->child )
             makeExprList( res->child );
    #ifdef DEBUG
         inde; fprintf(stderr,"</math:mrow>\n");
    #else
         rendEl("math:mrow");
    #endif
    }

    void Formula::makeExprList(Node *res)
    {
       if( !res ) return;
        Node *tmp = res->child;
        if( !tmp ) return ;

        if( tmp->id == ID_EXPRLIST ){
             Node *next = tmp->next;
             makeExprList( tmp ) ;
             if( next )
                  makeExpr( next );
        }
        else
             makeExpr( tmp );
    }

    void Formula::makeExpr(Node *res)
    {
      if( !res ) return;
        Node *tmp = res->child;
        if( !tmp ) return;
        switch( tmp->id ) {
            case ID_PRIMARYEXPR:
                 if( tmp->next ){
    #ifdef DEBUG
                     inds;
                     fprintf(stderr,"<math:mrow>\n");
    #else
                     rstartEl("math:mrow", mxList.get());
    #endif
                 }

                 makePrimary(tmp);

                 if( tmp->next ){
    #ifdef DEBUG
                     inde; fprintf(stderr,"</math:mrow>\n");
    #else
                     rendEl("math:mrow");
    #endif
                 }
                break;
             case ID_SUBEXPR:
             case ID_SUPEXPR:
             case ID_SUBSUPEXPR:
                 makeSubSup(tmp);
                 break;
             case ID_FRACTIONEXPR:
             case ID_OVER:
                 makeFraction(tmp);
                 break;
             case ID_DECORATIONEXPR:
                 makeDecoration(tmp);
                 break;
             case ID_SQRTEXPR:
             case ID_ROOTEXPR:
                 makeRoot(tmp);
                 break;
             case ID_ARROWEXPR:
                 break;
             case ID_ACCENTEXPR:
                 makeAccent(tmp);
                 break;
             case ID_PARENTH:
             case ID_ABS:
                 makeParenth(tmp);
                 break;
             case ID_FENCE:
                 makeFence(tmp);
                 break;
             case ID_BLOCK:
                 makeBlock(tmp);
                 break;
             case ID_BEGIN:
             case ID_END:
                 break;
        }
    }

    void Formula::makeIdentifier(Node *res)
    {
         Node *tmp = res;
      if( !tmp ) return;
      if( !tmp->value ) return;
         switch( tmp->id ){
         case ID_CHARACTER :
    #ifdef DEBUG
              inds;
              fprintf(stderr,"<math:mi>%s</math:mi>\n",tmp->value);
              indo;
    #else
              rstartEl("math:mi", mxList.get());
              rchars(OUString::createFromAscii(tmp->value));
              rendEl("math:mi");
    #endif
              break;
         case ID_STRING :
              {
    #ifdef DEBUG
    #else
                    rstartEl("math:mi", mxList.get());
                    reucstr(tmp->value, strlen(tmp->value));
                    rendEl("math:mi");
    #endif
              }
              break;
         case ID_IDENTIFIER :
    #ifdef DEBUG
              inds;
              fprintf(stderr,"<math:mi>%s</math:mi>\n",
                      getMathMLEntity(tmp->value).c_str());
              indo;
    #else
              rstartEl("math:mi", mxList.get());
              runistr(reinterpret_cast<sal_Unicode const *>(getMathMLEntity(tmp->value).c_str()));
              rendEl("math:mi");
    #endif
              break;
         case ID_NUMBER :
    #ifdef DEBUG
              inds;
              fprintf(stderr,"<math:mn>%s</math:mn>\n",tmp->value);
              indo;
    #else
              rstartEl("math:mn", mxList.get());
              rchars(OUString::createFromAscii(tmp->value));
              rendEl("math:mn");
    #endif
              break;
         case ID_OPERATOR :
         case ID_DELIMETER :
            {
    #ifdef DEBUG
              inds; fprintf(stderr,"<math:mo>%s</math:mo>\n",tmp->value); indo;
    #else
              rstartEl("math:mo", mxList.get());
              runistr(reinterpret_cast<sal_Unicode const *>(getMathMLEntity(tmp->value).c_str()));
              rendEl("math:mo");
    #endif
              break;
            }
         }
    }
    void Formula::makePrimary(Node *res)
    {
         Node *tmp = res;
         if( !tmp ) return ;
         if( tmp->child ){
              if( tmp->child->id == ID_PRIMARYEXPR ){
                    makePrimary(tmp->child);
              }
              else{
                    makeIdentifier(tmp->child);
              }
         }
         if( tmp->next ){
              makeIdentifier(tmp->next);
         }
    }

    void Formula::makeSubSup(Node *res)
    {
         Node *tmp = res;
         if( !tmp ) return;

    #ifdef DEBUG
         inds;
         if( res->id == ID_SUBEXPR )
              fprintf(stderr,"<math:msub>\n");
         else if( res->id == ID_SUPEXPR )
              fprintf(stderr,"<math:msup>\n");
         else
              fprintf(stderr,"<math:msubsup>\n");
    #else
         if( res->id == ID_SUBEXPR )
              rstartEl("math:msub", mxList.get());
         else if( res->id == ID_SUPEXPR )
              rstartEl("math:msup", mxList.get());
         else
              rstartEl("math:msubsup", mxList.get());
    #endif

         tmp = tmp->child;
         if( res->id == ID_SUBSUPEXPR ) {
              makeExpr(tmp);
              makeBlock(tmp->next);
              makeBlock(tmp->next->next);
         }
         else{
              makeExpr(tmp);
              makeExpr(tmp->next);
         }

    #ifdef DEBUG
         inde;
         if( res->id == ID_SUBEXPR )
              fprintf(stderr,"</math:msub>\n");
         else if( res->id == ID_SUPEXPR )
              fprintf(stderr,"</math:msup>\n");
         else
              fprintf(stderr,"</math:msubsup>\n");
    #else
         if( res->id == ID_SUBEXPR )
              rendEl("math:msub");
         else if( res->id == ID_SUPEXPR )
              rendEl("math:msup");
         else
              rendEl("math:msubsup");
    #endif
    }

    void Formula::makeFraction(Node *res)
    {
         Node *tmp = res;
         if( !tmp ) return;

    #ifdef DEBUG
         inds;
         fprintf(stderr,"<math:mfrac>\n");
    #else
         rstartEl("math:mfrac", mxList.get());
    #endif

         tmp = tmp->child;
    #ifdef DEBUG
         inds;
         fprintf(stderr,"<math:mrow>\n");
    #else
         rstartEl("math:mrow", mxList.get());
    #endif

         if( res->id == ID_FRACTIONEXPR )
              makeBlock(tmp);
         else
              makeExprList(tmp);

    #ifdef DEBUG
         inde;
         fprintf(stderr,"</math:mrow>\n");
         inds;
         fprintf(stderr,"<math:mrow>\n");
    #else
         rendEl("math:mrow");
         rstartEl("math:mrow", mxList.get());
    #endif

         if( res->id == ID_FRACTIONEXPR )
              makeBlock(tmp->next);
         else
              makeExprList(tmp->next);

    #ifdef DEBUG
         inde;
         fprintf(stderr,"</math:mrow>\n");
         inde;
         fprintf(stderr,"</math:mfrac>\n");
    #else
         rendEl("math:mrow");
         rendEl("math:mfrac");
    #endif
    }

    void Formula::makeDecoration(Node *res)
    {
         int isover = 1;
         Node *tmp = res->child;
         if( !tmp ) return;
         if( !strncmp(tmp->value,"under", 5) )
              isover = 0;
    #ifdef DEBUG
         inds;
         if( isover )
              fprintf(stderr,"<math:mover>\n");
         else
              fprintf(stderr,"<math:munder>\n");
    #else
         /* FIXME: no idea when 'accent' is true or false. */
         if( isover ){
              padd("accent","CDATA","true");
              rstartEl("math:mover", mxList.get());
         }
         else{
              padd("accentunder","CDATA","true");
              rstartEl("math:munder", mxList.get());
         }
         mxList->clear();
    #endif

         makeBlock(tmp->next);

    #ifdef DEBUG
         inds;
         fprintf(stderr,"<math:mo>%s</math:mo>\n",
                 getMathMLEntity(tmp->value).c_str());
         indo;
    #else
         rstartEl("math:mo", mxList.get());
         runistr(reinterpret_cast<sal_Unicode const *>(getMathMLEntity(tmp->value).c_str()));
         rendEl("math:mo");
    #endif

    #ifdef DEBUG
         inde;
         if( isover )
              fprintf(stderr,"</math:mover>\n");
         else
              fprintf(stderr,"</math:munder>\n");
    #else
         if( isover )
              rendEl("math:mover");
         else
              rendEl("math:munder");
    #endif
    }

    void Formula::makeRoot(Node *res)
    {
         Node *tmp = res;
         if( !tmp ) return;
    #ifdef DEBUG
         inds;
         if( tmp->id == ID_SQRTEXPR )
              fprintf(stderr,"<math:msqrt>\n");
         else
              fprintf(stderr,"<math:mroot>\n");
    #else
         if( tmp->id == ID_SQRTEXPR )
              rstartEl("math:msqrt", mxList.get());
         else
              rstartEl("math:mroot", mxList.get());
    #endif

         if( tmp->id == ID_SQRTEXPR ){
              makeBlock(tmp->child);
         }
         else{
              makeBracket(tmp->child);
              makeBlock(tmp->child->next);
         }

    #ifdef DEBUG
         inde;
         if( tmp->id == ID_SQRTEXPR )
              fprintf(stderr,"</math:msqrt>\n");
         else
              fprintf(stderr,"</math:mroot>\n");
    #else
         if( tmp->id == ID_SQRTEXPR )
              rendEl("math:msqrt");
         else
              rendEl("math:mroot");
    #endif
    }
    void Formula::makeAccent(Node *res)
    {
         makeDecoration( res );
    }
    void Formula::makeParenth(Node *res)
    {
         Node *tmp = res;
         if( !tmp ) return;
    #ifdef DEBUG
         inds;
         fprintf(stderr,"<math:mrow>\n");
         inds;
         if( tmp->id == ID_PARENTH ){
              fprintf(stderr,"<math:mo>(</math:mo>\n");
         }
         else
              fprintf(stderr,"<math:mo>|</math:mo>\n");
         indo; inds;
         fprintf(stderr,"<math:mrow>\n");
    #else
         rstartEl("math:mrow", mxList.get());
         rstartEl("math:mo", mxList.get());
         if( tmp->id == ID_PARENTH )
              rchars("(");
         else
              rchars("|");
         rendEl("math:mo");
         rstartEl("math:mrow", mxList.get());
    #endif

         if( tmp->child )
              makeExprList(tmp->child);

    #ifdef DEBUG
         inde;
         fprintf(stderr,"</math:mrow>\n");
         inds;
         if( tmp->id == ID_PARENTH )
              fprintf(stderr,"<math:mo>)</math:mo>\n");
         else
              fprintf(stderr,"<math:mo>|</math:mo>\n");
         indo;
         inde;
         fprintf(stderr,"</math:mrow>\n");
    #else
         rendEl("math:mrow");
         rstartEl("math:mo", mxList.get());
         if( tmp->id == ID_PARENTH )
              rchars(")");
         else
              rchars("|");
         rendEl("math:mo");
         rendEl("math:mrow");
    #endif
    }

    void Formula::makeFence(Node *res)
    {
         Node *tmp = res->child;
    #ifdef DEBUG
         inds;
         fprintf(stderr,"<math:mfenced open=\"%s\" close=\"%s\">\n",
                    getMathMLEntity(tmp->value).c_str(),
                    getMathMLEntity(tmp->next->next->value).c_str());
    #else
         padd("open", "CDATA",
                 OUString(reinterpret_cast<sal_Unicode const *>(getMathMLEntity(tmp->value).c_str())));
         padd("close", "CDATA",
                 OUString(reinterpret_cast<sal_Unicode const *>(getMathMLEntity(tmp->next->next->value).c_str())));
         rstartEl("math:mfenced", mxList.get());
         mxList->clear();
    #endif

         makeExprList(tmp->next);

    #ifdef DEBUG
         inde;
         fprintf(stderr,"</math:mfenced>\n");
    #else
         rendEl("math:mfenced");
    #endif
    }

    void Formula::makeBracket(Node *res)
    {
         makeBlock(res);
    }

    void Formula::makeBlock(Node *res)
    {
    #ifdef DEBUG
         inds;
         fprintf(stderr,"<math:mrow>\n");
    #else
         rstartEl("math:mrow", mxList.get());
    #endif

         if( res->child )
              makeExprList(res->child);

    #ifdef DEBUG
         inde;
         fprintf(stderr,"</math:mrow>\n");
    #else
         rendEl("math:mrow");
    #endif
    }

    void Formula::parse()
    {
         Node *res = nullptr;
         if( !eq ) return;

         MzString a;
         // fprintf(stderr,"\n\n[BEFORE]\n[%s]\n",eq);
         eq2latex(a,eq);

         int idx=a.find(sal::static_int_cast<char>(0xff));
         while(idx){
               //printf("idx = [%d]\n",idx);
               a.replace(idx,0x20);
               if((idx = a.find(sal::static_int_cast<char>(0xff),idx+1)) < 0)
                    break;
         }

         char *buf = static_cast<char *>(malloc(a.length()+1));
         bool bStart = false;
         int i, j;
         for( i = 0, j=0 ; i < a.length() ; i++){ // rtrim and ltrim 32 10 13
               if( bStart ){
                    buf[j++] = a[i];
               }
               else{
                    if( a[i] != 32 && a[i] != 10 && a[i] != 13){
                         bStart = true;
                         buf[j++] = a[i];
                    }
               }
         }
         buf[j] = 0;
         for( i = j-1 ; i >= 0 ; i++ ){
               if( buf[i] == 32 || buf[i] == 10 || buf[i] == 13 ){
                    buf[i] = 0;
               }
               else
                    break;
         }
         // fprintf(stderr,"\n\n[RESULT]\n[%s]\n",a.c_str());
         if( buf[0] != '\0' )
               res = mainParse( a.c_str() );
         else
               res = nullptr;
         free(buf);

         if( res ){
              makeMathML( res );
         }
         for (const auto &node : nodelist)
             delete node;
         nodelist.clear();
    }

    void Formula::trim()
    {
         int len = strlen(eq);
         char *buf = static_cast<char *>(malloc(len+1));
         bool bStart = false;
         int i, j;
         for( i = 0, j=0 ; i < len ; i++){ // rtrim and ltrim 32 10 13
              if( bStart ){
                    buf[j++] = eq[i];
              }
              else{
                    if( eq[i] != 32 && eq[i] != 10 && eq[i] != 13){
                         bStart = true;
                         buf[j++] = eq[i];
                    }
              }
         }
         buf[j] = 0;
         for( i = j-1 ; i >= 0 ; i++ ){
              if( buf[i] == 32 || buf[i] == 10 || buf[i] == 13 ){
                    buf[i] = 0;
              }
              else
                    break;
         }
         if( buf[0] != '\0' )
              strcpy(eq, buf);
         else
              eq = nullptr;
         free(buf);
    }

    /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

↑ V522 There might be dereferencing of a potential null pointer 'buf'. Check lines: 594, 584.

↑ V522 There might be dereferencing of a potential null pointer 'buf'. Check lines: 634, 624.