Files
Yajbir Singh f1b860b25c
Some checks failed
check / markdownlint (push) Has been cancelled
check / spellchecker (push) Has been cancelled
updated
2025-12-11 19:03:17 +05:30

791 lines
16 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* (c) Copyright Ascensio System SIA 2010-2023
*
* This program is a free software product. You can redistribute it and/or
* modify it under the terms of the GNU Affero General Public License (AGPL)
* version 3 as published by the Free Software Foundation. In accordance with
* Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
* that Ascensio System SIA expressly excludes the warranty of non-infringement
* of any third-party rights.
*
* This program is distributed WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For
* details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
*
* You can contact Ascensio System SIA at 20A-6 Ernesta Birznieka-Upish
* street, Riga, Latvia, EU, LV-1050.
*
* The interactive user interfaces in modified source and object code versions
* of the Program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU AGPL version 3.
*
* Pursuant to Section 7(b) of the License you must retain the original Product
* logo when distributing the program. Pursuant to Section 7(e) we decline to
* grant you any rights under trademark law for use of our trademarks.
*
* All the Product's GUI elements, including illustrations and icon sets, as
* well as technical writing content are licensed under the terms of the
* Creative Commons Attribution-ShareAlike 4.0 International. See the License
* terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
*
*/
#include "MathEquation.h"
#include "OutputDev.h"
using namespace MathEquation;
#define CHECK_OPEN_BRACKET(nVaritation) ((0 == nVariation) || (1 == nVariation))
#define CHECK_CLOSE_BRACKET(nVaritation) ((0 == nVariation) || (2 == nVariation))
#define CHECK_SUP(nVariation) ((0 == nVariation) || (2 == nVariation))
#define CHECK_SUB(nVariation) ((1 == nVariation) || (2 == nVariation))
#define GET_BARLINE_TYPE(nVariation) (0 == nVariation? bartypeLine : bartypeDoubleLine)
#define GET_BARARROW_TYPE(nVariation) (0 == nVariation? bartypeArrowLeft : (1 == nVariation? bartypeArrowRight : bartypeArrowDouble))
CEquationReader::CEquationReader(const wchar_t* wsFilePath) : m_oStorage(wsFilePath), pStm(NULL), pS(NULL), nHAlign(0), nVAlign(0)
{
InitSizes();
}
CEquationReader::~CEquationReader()
{
if (NULL != pS)
delete pS;
if (NULL != pStm)
delete pStm;
}
void CEquationReader::InitSizes()
{
//todo обработать open(true/false)
m_oStorage.open(false, false);
// Выставляем размеры текста по умолчанию (если они изменены, тогда ничего не поделаешь, т.к. это не сохраняется в самом файле)
aSizeTable[0] = 12;
aSizeTable[1] = 7;
aSizeTable[2] = 5;
aSizeTable[3] = 18;
aSizeTable[4] = 12;
}
void CEquationReader::SetOutputDev(IOutputDev *pOutput)
{
pOutputDev = pOutput;
InitFonts();
}
void CEquationReader::InitFonts()
{
// Стандартные шрифты для MathEquation со стандартными настройками стилей.
// (если они изменены, тогда ничего не поделаешь, т.к. это не сохраняется в самом файле)
if (pOutputDev)
{
for(unsigned char i = 1; i <= 8; i++)
{
switch(i)
{
case 1: pOutputDev->AddFont(i + 128, "Times New Roman", false, false); break; // текст
case 2: pOutputDev->AddFont(i + 128, "Times New Roman", false, false); break; // функция
case 3: pOutputDev->AddFont(i + 128, "Times New Roman", false, true); break; // переменная
case 4: pOutputDev->AddFont(i + 128, "Symbol", false, true); break; // ст. греческие
case 5: pOutputDev->AddFont(i + 128, "Symbol", false, false); break; // пр. греческие
case 6: pOutputDev->AddFont(i + 128, "Symbol", false, false); break; // символ
case 7: pOutputDev->AddFont(i + 128, "Times New Roman", true, false); break; // матрица-вектор
case 8: pOutputDev->AddFont(i + 128, "Times New Roman", false, false); break; // числа
}
}
}
}
int CEquationReader::Parse()
{
//если смотреть реализацию, то pStm можно удалить после конструтора CLEStream,
//но если не смотреть реализацию,то правильно удалить pStm после pS
pStm = new POLE::Stream( &m_oStorage, L"Equation Native");
pS = new CLEStream<Stream>(pStm);
if (!pS->IsValid())
return 0;
*pS >> oHeader.nCBHdr; // length of header, sizeof(CEquationHeader) = 28
*pS >> oHeader.nVersion; // hiword = 2, loword = 0
*pS >> oHeader.nCf; // clipboard format ("MathType EF")
*pS >> oHeader.nCBObject; // length of MTEF data following this header
*pS >> oHeader.nReserved1; // not used
*pS >> oHeader.nReserved2; // not used
*pS >> oHeader.nReserved3; // not used
*pS >> oHeader.nReserved4; // not used
*pS >> nVersion;
*pS >> nPlatform;
*pS >> nProduct;
*pS >> nProdVersion;
*pS >> nProdSubVersion;
if (nVersion > 3)
return 0;
pOutputDev->BeginEquation();
int nRet = HandleRecords();
pOutputDev->EndEquation();
return nRet;
}
int CEquationReader::HandleRecords()
{
unsigned char nTag, nRecord;
//_UINT16 nTabOffset;
int nRet = 1;
int nCurRow = 0;
int nCurCol = 0;
int nPart = 0;
do
{
*pS >> nTag;
nRecord = nTag & 0x0F;
switch(nRecord)
{
case LINE:
if (xfLMOVE(nTag))
HandleNudge();
//if (xfLSPACE(nTag))
//if (xfRULER(nTag))
if (!(xfNULL(nTag)))
{
pOutputDev->BeginBlock();
nRet = HandleRecords();
pOutputDev->EndBlock();
}
break;
case CHAR:
if (xfLMOVE(nTag))
HandleNudge();
nRet = HandleChar(nTag);
break;
case TMPL:
if (xfLMOVE(nTag))
HandleNudge();
nRet = HandleTemplate();
break;
case PILE:
if (xfLMOVE(nTag))
HandleNudge();
nRet = HandlePile();
break;
case MATRIX:
if (xfLMOVE(nTag))
HandleNudge();
nRet = HandleMatrix();
break;
case EMBEL:
if (xfLMOVE(nTag))
HandleNudge();
HandleEmblishments();
break;
case RULER:
HandleRuler();
break;
case FONT:
HandleFont();
break;
case SIZE_CUSTOM:
case SIZE_REGULAR:
case SIZE_BIGSCRIPT:
case SIZE_SMALLSCRIT:
case SIZE_BIGSYMBOL:
case SIZE_SMALLSYMBOL:
HandleSetSize((MTOKENS)nRecord);
break;
case END:
default:
break;
}
}
while (nRecord != END && !pS->IsEof());
return nRet;
}
void CEquationReader::HandleNudge()
{
unsigned char nXNudge; *pS >> nXNudge;
unsigned char nYNudge; *pS >> nYNudge;
if (128 == nXNudge && 128 == nYNudge)
{
_UINT16 nXLongNudge; *pS >> nXLongNudge;
_UINT16 nYLongNudge; *pS >> nYLongNudge;
}
}
int CEquationReader::HandleChar(unsigned char nTag)
{
unsigned short nChar;
int nRet = 1;
if (xfAUTO(nTag))
{
//This is a candidate for function recognition, whatever
//that is!
}
unsigned char nTypeFace;
*pS >> nTypeFace;
if (nVersion < 3)
{
unsigned char nChar8;
*pS >> nChar8;
nChar = nChar8;
}
else
*pS >> nChar;
// bad character, old mathtype < 3 has these
if (nChar < 0x20)
return nRet;
pOutputDev->BeginChar(nChar, nTypeFace, IsSpecialChar(nChar));
if (xfEMBELL(nTag))
{
nRet = HandleRecords();
}
pOutputDev->EndChar();
return nRet;
}
int CEquationReader::HandleTemplate()
{
unsigned char nSelector, nVariation, nOption;
*pS >> nSelector;
*pS >> nVariation;
*pS >> nOption;
HandleStartTemplate(nSelector, nVariation);
int nRet = HandleRecords();
HandleEndTemplate(nSelector, nVariation);
return nRet;
}
void CEquationReader::HandleStartTemplate(unsigned char nSelector, unsigned char nVariation)
{
switch (nSelector)
{
case 0x00:
case 0x01:
case 0x02:
case 0x03:
case 0x04:
case 0x05:
case 0x06:
case 0x07:
case 0x08:
case 0x09:
case 0x0a:
case 0x0b:
case 0x0c:
pOutputDev->BeginBrackets((MBRACKETSTYPE)nSelector, CHECK_OPEN_BRACKET(nVariation), CHECK_CLOSE_BRACKET(nVariation));
break;
case 0xd:
pOutputDev->BeginRoot(0 == nVariation ? false : true);
break;
case 0xe:
pOutputDev->BeginFraction(fractionRegular, 1 == nVariation);
break;
case 0xf:
pOutputDev->BeginScript(scriptalignRight, false, 0 == nVariation || 2 == nVariation, 1 == nVariation || 2 == nVariation, true);
break;
case 0x10:
pOutputDev->BeginBar(GET_BARLINE_TYPE(nVariation), false);
break;
case 0x11:
pOutputDev->BeginBar(GET_BARLINE_TYPE(nVariation), true);
break;
case 0x12:
pOutputDev->BeginArrow(arrowtypeLeft, 0 == nVariation ? true : false);
break;
case 0x13:
pOutputDev->BeginArrow(arrowtypeRight, 0 == nVariation ? true : false);
break;
case 0x14:
pOutputDev->BeginArrow(arrowtypeDouble, 0 == nVariation ? true : false);
break;
case 0x15:
pOutputDev->BeginIntegral((MINTEGRALTYPE)(nVariation));
break;
case 0x16:
pOutputDev->BeginIntegral((MINTEGRALTYPE)(nVariation + (BYTE)integraltypeDouble));
break;
case 0x17:
pOutputDev->BeginIntegral((MINTEGRALTYPE)(nVariation + (BYTE)integraltypeTriple));
break;
case 0x18:
pOutputDev->BeginIntegral((MINTEGRALTYPE)(nVariation + (BYTE)integraltypeSingleCSubSup));
break;
case 0x19:
pOutputDev->BeginIntegral((MINTEGRALTYPE)(nVariation + (BYTE)integraltypeDoubleOrientedCSub));
break;
case 0x1a:
pOutputDev->BeginIntegral((MINTEGRALTYPE)(nVariation + (BYTE)integraltypeTripleOrientedCSub));
break;
case 0x1b:
pOutputDev->BeginVerticalBrace(true);
break;
case 0x1c:
pOutputDev->BeginVerticalBrace(false);
break;
case 0x1d:
pOutputDev->BeingNArray((MNARRAYTYPE)nVariation);
break;
case 0x1e:
pOutputDev->BeingNArray((MNARRAYTYPE)(nVariation + narySumRSub));
break;
case 0x1f:
pOutputDev->BeingNArray((MNARRAYTYPE)(nVariation + naryProdCSub));
break;
case 0x20:
pOutputDev->BeingNArray((MNARRAYTYPE)(nVariation + naryProdRSub));
break;
case 0x21:
pOutputDev->BeingNArray((MNARRAYTYPE)(nVariation + naryCoProdCSub));
break;
case 0x22:
pOutputDev->BeingNArray((MNARRAYTYPE)(nVariation + naryCoProdRSub));
break;
case 0x23:
pOutputDev->BeingNArray((MNARRAYTYPE)(nVariation + naryUnionCSub));
break;
case 0x24:
pOutputDev->BeingNArray((MNARRAYTYPE)(nVariation + naryUnionRSub));
break;
case 0x25:
pOutputDev->BeingNArray((MNARRAYTYPE)(nVariation + naryIntersectCSub));
break;
case 0x26:
pOutputDev->BeingNArray((MNARRAYTYPE)(nVariation + naryIntersectRSub));
break;
case 0x27:
pOutputDev->BeginScript(scriptalignCenter, true, CHECK_SUP(nVariation), CHECK_SUB(nVariation), true);
break;
case 0x28:
pOutputDev->BeginLongDivision((MLONGDIVISION)nVariation);
break;
case 0x29:
pOutputDev->BeginFraction(fractionSlanted, 1 == nVariation);
break;
case 0x2a:
pOutputDev->BeginScript(scriptalignRight, true, CHECK_SUP(nVariation), CHECK_SUB(nVariation), false);
break;
case 0x2b:
pOutputDev->BeginScript(scriptalignCenter, true, CHECK_SUP(nVariation), CHECK_SUB(nVariation), false);
break;
case 0x2c:
pOutputDev->BeginScript(scriptalignLeft, false, 0 == nVariation || 2 == nVariation, 1 == nVariation || 2 == nVariation, true);
break;
case 0x2d:
pOutputDev->BeginAngleBracketsWithSeparator((MANGLEBRACKETSWITHSEPARATORTYPE)nVariation);
break;
case 0x2e:
pOutputDev->BeginBar(GET_BARARROW_TYPE(nVariation), false);
break;
case 0x2f:
pOutputDev->BeginBar(GET_BARARROW_TYPE(nVariation), true);
break;
default:
break;
}
}
void CEquationReader::HandleEndTemplate(unsigned char nSelector, unsigned char nVariation)
{
switch (nSelector)
{
case 0x0:
case 0x1:
case 0x2:
case 0x3:
case 0x4:
case 0x5:
case 0x6:
case 0x7:
case 0x8:
case 0x9:
case 0xa:
case 0xb:
case 0xc:
pOutputDev->EndBrackets((MBRACKETSTYPE)nSelector, CHECK_OPEN_BRACKET(nVariation), CHECK_CLOSE_BRACKET(nVariation));
break;
case 0xd:
pOutputDev->EndRoot();
break;
case 0xe:
pOutputDev->EndFraction();
break;
case 0xf:
pOutputDev->EndScript();
break;
case 0x2c:
pOutputDev->EndScript();
break;
case 0x2e:
case 0x2f:
pOutputDev->EndBar();
break;
case 0x10:
case 0x11:
pOutputDev->EndBar();
break;
case 0x12:
case 0x13:
case 0x14:
pOutputDev->EndArrow();
break;
case 0x1b:
pOutputDev->EndVerticalBrace();
break;
case 0x1c:
pOutputDev->EndVerticalBrace();
break;
case 0x27:
pOutputDev->EndScript();
break;
case 0x28:
pOutputDev->EndLongDivision();
break;
case 0x29:
pOutputDev->EndFraction();
break;
case 0x1d:
case 0x1e:
case 0x1f:
case 0x20:
case 0x21:
case 0x22:
case 0x23:
case 0x24:
case 0x25:
case 0x26:
pOutputDev->EndNArray();
break;
case 0x15:
case 0x16:
case 0x17:
case 0x18:
case 0x19:
case 0x1a:
pOutputDev->EndIntegral();
break;
case 0x2a:
case 0x2b:
pOutputDev->EndScript();
break;
case 0x2d:
pOutputDev->EndAngleBracketsWithSeparator();
break;
default:
break;
}
}
int CEquationReader::HandlePile()
{
int nSetAlign = 0;
*pS >> nHAlign;
*pS >> nVAlign;
pOutputDev->StartPile(nHAlign, nVAlign);
int nRet = HandleRecords();
pOutputDev->EndPile();
return nRet;
}
int CEquationReader::HandleMatrix()
{
unsigned char nHorAlign, nVerAlign, nRows, nCols;
*pS >> nVAlign;
*pS >> nHorAlign;
*pS >> nVerAlign;
*pS >> nRows;
*pS >> nCols;
bool bEqualRows = nHorAlign & 0xf0;
nHorAlign &= 0xf;
bool bEqualCols = nVerAlign & 0xf0;
nVerAlign &= 0xf;
int nBytes = ((nRows + 1) * 2) / 8;
if (((nRows + 1) * 2) % 8)
nBytes++;
unsigned char *pVerBorders = new unsigned char[nRows + 1];
unsigned char nTempByte;
for (int nByteIndex = 0, nRowIndex = 0, nBitIndex = 0; nByteIndex < nBytes; nByteIndex++, nBitIndex = 0)
{
*pS >> nTempByte;
while(nRowIndex < nRows + 1 && nBitIndex < 8)
{
pVerBorders[nRowIndex] = (nTempByte >> nBitIndex) & 0x03;
nBitIndex += 2;
nRowIndex++;
}
}
nBytes = ((nCols + 1) * 2) / 8;
if (((nCols + 1) * 2) % 8)
nBytes++;
unsigned char *pHorBorders = new unsigned char[nCols + 1];
for (int nByteIndex = 0, nColIndex = 0, nBitIndex = 0; nByteIndex < nBytes; nByteIndex++, nBitIndex = 0)
{
*pS >> nTempByte;
while(nColIndex < nCols + 1 && nBitIndex < 8)
{
pHorBorders[nColIndex] = (nTempByte >> nBitIndex) & 0x03;
nBitIndex += 2;
nColIndex++;
}
}
pOutputDev->BeginMatrix(nVAlign, (MMATRIXHORALIGN)nHorAlign, (MMATRIXVERALIGN)nVerAlign, bEqualRows, bEqualCols, nRows, nCols, pVerBorders, pHorBorders);
delete []pVerBorders;
delete []pHorBorders;
int nRet = HandleRecords();
pOutputDev->EndMatrix();
return nRet;
}
void CEquationReader::HandleEmblishments()
{
unsigned char nEmbel;
do
{
*pS >> nEmbel;
if (nEmbel >= embelMin && nEmbel <= embelMax)
pOutputDev->AddCharEmbel((MEMBELTYPE)nEmbel);
if (nVersion < 3)
break;
}while (nEmbel);
}
void CEquationReader::HandleSetSize(MTOKENS eType)
{
if (SIZE_CUSTOM == eType)
{
unsigned char nTemp;
*pS >> nTemp;
_UINT16 nSize;
switch (nTemp)
{
case 101:
{
*pS >> nSize;
break;
}
case 100:
{
// TODO: Проверить эту ветку
*pS >> nTemp;
nSize = nTemp;
_UINT16 nTempSize;
*pS >> nTempSize;
break;
}
default:
{
// TODO: Проверить эту ветку
nSize = nTemp;
*pS >> nTemp;
_UINT16 nTempSize = nTemp - 128;
break;
}
}
pOutputDev->SetSize(nSize / 32);
}
else if (SIZE_BIGSCRIPT == eType || SIZE_BIGSYMBOL == eType || SIZE_REGULAR == eType || SIZE_SMALLSCRIT == eType || SIZE_SMALLSYMBOL == eType)
{
int nIndex = (int)eType - (int)SIZE_REGULAR;
pOutputDev->SetSize(aSizeTable[nIndex]);
}
}
void CEquationReader::HandleRuler()
{
unsigned char nTabType, nTabStops;
_UINT16 nTabOffset;
*pS >> nTabStops;
for (int nTabIndex = 0; nTabIndex < nTabStops; nTabIndex++)
{
*pS >> nTabType;
*pS >> nTabOffset;
}
}
void CEquationReader::HandleFont()
{
unsigned char nTFace, nStyle;
String sName;
*pS >> nTFace;
*pS >> nStyle;
char nChar8;
do
{
*pS >> nChar8;
sName += nChar8;
}
while(nChar8);
pOutputDev->AddFont(128 - nTFace, sName.GetValue(), nStyle & 0x01, nStyle & 0x02);
}
bool CEquationReader::IsSpecialChar(unsigned short nChar)
{
switch(nChar)
{
case 0xeb00: // Alignment Symbol
case 0xeb01: // Zerospace
case 0xeb02: // thin space
case 0xeb04: // thick space
case 0xeb05: // large space
case 0xeb08: // 1pt space
return true;
}
return false;
}