mirror of
https://github.com/ONLYOFFICE/core.git
synced 2026-07-11 14:00:32 +08:00
git-svn-id: svn://fileserver/activex/AVS/Sources/TeamlabOffice/trunk/ServerComponents@62480 954022d7-b5bf-4e40-9824-e11837661b57
1867 lines
42 KiB
C++
1867 lines
42 KiB
C++
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <ctype.h>
|
|
#include <math.h>
|
|
#include "MemoryUtils.h"
|
|
#include "Object.h"
|
|
#include "Dict.h"
|
|
#include "Stream.h"
|
|
#include "Function.h"
|
|
|
|
namespace PdfReader
|
|
{
|
|
//------------------------------------------------------------------------
|
|
// Function
|
|
//------------------------------------------------------------------------
|
|
|
|
Function::Function()
|
|
{
|
|
}
|
|
|
|
Function::~Function()
|
|
{
|
|
}
|
|
|
|
Function *Function::Parse(Object *pFuncObject)
|
|
{
|
|
Dict *pDict;
|
|
|
|
// Ôóíêöèÿ çàäàåòñÿ ëèáî êàê ñëîâàðü, ëèáî ïîòîê, ëèáî êàê òîæäåñòâåííàÿ ôóíêöèÿ
|
|
if (pFuncObject->IsStream())
|
|
{
|
|
pDict = pFuncObject->StreamGetDict();
|
|
}
|
|
else if (pFuncObject->IsDict())
|
|
{
|
|
pDict = pFuncObject->GetDict();
|
|
}
|
|
else if (pFuncObject->IsName("Identity"))
|
|
{
|
|
return new IdentityFunction();
|
|
}
|
|
else
|
|
{
|
|
// TO DO: Error "Expected function dictionary or stream"
|
|
return NULL;
|
|
}
|
|
|
|
Object oTemp;
|
|
if (!pDict->Search("FunctionType", &oTemp)->IsInt())
|
|
{
|
|
// TO DO: Error "Function type is missing or wrong type"
|
|
oTemp.Free();
|
|
return NULL;
|
|
}
|
|
int nFuncType = oTemp.GetInt();
|
|
oTemp.Free();
|
|
|
|
Function *pFunc = NULL;
|
|
if (0 == nFuncType) // Sampled function
|
|
{
|
|
pFunc = new SampledFunction(pFuncObject, pDict);
|
|
}
|
|
else if (2 == nFuncType) // Exponential interpolation function
|
|
{
|
|
pFunc = new ExponentialFunction(pFuncObject, pDict);
|
|
}
|
|
else if (3 == nFuncType) // Stitching function
|
|
{
|
|
pFunc = new StitchingFunction(pFuncObject, pDict);
|
|
}
|
|
else if (4 == nFuncType) // PostScript calculator function
|
|
{
|
|
pFunc = new PostScriptFunction(pFuncObject, pDict);
|
|
}
|
|
else
|
|
{
|
|
// TO DO: Error "Unimplemented function type"
|
|
return NULL;
|
|
}
|
|
if (!pFunc->IsValid())
|
|
{
|
|
delete pFunc;
|
|
return NULL;
|
|
}
|
|
|
|
return pFunc;
|
|
}
|
|
|
|
bool Function::Initialize(Dict *pDict)
|
|
{
|
|
Object oArray;
|
|
// Domain (Âñåãäà äîëæåí ïðèñóòñòâîâàòü)
|
|
if (!pDict->Search("Domain", &oArray)->IsArray())
|
|
{
|
|
// TO DO: Error "Function is missing domain"
|
|
oArray.Free();
|
|
return false;
|
|
}
|
|
m_nInputDim = oArray.ArrayGetLength() / 2;
|
|
|
|
if (m_nInputDim > funcMaxInputs)
|
|
{
|
|
// TO DO: Error "Functions with more than funcMaxInputs inputs are unsupported"
|
|
oArray.Free();
|
|
return false;
|
|
}
|
|
for (int nIndex = 0; nIndex < m_nInputDim; ++nIndex)
|
|
{
|
|
Object oTemp;
|
|
oArray.ArrayGet(2 * nIndex, &oTemp);
|
|
if (!oTemp.IsNum())
|
|
{
|
|
// TO DO: Error "Illegal value in function domain array"
|
|
oTemp.Free();
|
|
oArray.Free();
|
|
return false;
|
|
}
|
|
m_arrDomain[nIndex][0] = oTemp.GetNum();
|
|
oTemp.Free();
|
|
oArray.ArrayGet(2 * nIndex + 1, &oTemp);
|
|
if (!oTemp.IsNum())
|
|
{
|
|
// TO DO: Error "Illegal value in function domain array"
|
|
oTemp.Free();
|
|
oArray.Free();
|
|
return false;
|
|
}
|
|
m_arrDomain[nIndex][1] = oTemp.GetNum();
|
|
oTemp.Free();
|
|
}
|
|
oArray.Free();
|
|
|
|
// Range (Ýòîãî ïîëÿ ìîæåò è íå áûòü)
|
|
m_bHasRange = false;
|
|
m_nOutputDim = 0;
|
|
if (pDict->Search("Range", &oArray)->IsArray())
|
|
{
|
|
m_bHasRange = true;
|
|
m_nOutputDim = oArray.ArrayGetLength() / 2;
|
|
if (m_nOutputDim > funcMaxOutputs)
|
|
{
|
|
// TO DO: Error "Functions with more than funcMaxOutputs outputs are unsupported"
|
|
oArray.Free();
|
|
return false;
|
|
}
|
|
for (int nIndex = 0; nIndex < m_nOutputDim; ++nIndex)
|
|
{
|
|
Object oTemp;
|
|
oArray.ArrayGet(2 * nIndex, &oTemp);
|
|
if (!oTemp.IsNum())
|
|
{
|
|
// TO DO: Error "Illegal value in function range array"
|
|
oTemp.Free();
|
|
oArray.Free();
|
|
return false;
|
|
}
|
|
m_arrRange[nIndex][0] = oTemp.GetNum();
|
|
oTemp.Free();
|
|
oArray.ArrayGet(2 * nIndex + 1, &oTemp);
|
|
if (!oTemp.IsNum())
|
|
{
|
|
// TO DO: Error "Illegal value in function range array"
|
|
oTemp.Free();
|
|
oArray.Free();
|
|
return false;
|
|
}
|
|
m_arrRange[nIndex][1] = oTemp.GetNum();
|
|
oTemp.Free();
|
|
}
|
|
}
|
|
oArray.Free();
|
|
|
|
return true;
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
// IdentityFunction
|
|
//------------------------------------------------------------------------
|
|
|
|
IdentityFunction::IdentityFunction()
|
|
{
|
|
// Çàïîëíÿåì ïðîèçâîëüíûìè çíà÷åíèÿìè
|
|
m_nInputDim = funcMaxInputs;
|
|
m_nOutputDim = funcMaxOutputs;
|
|
|
|
for (int nIndex = 0; nIndex < funcMaxInputs; ++nIndex)
|
|
{
|
|
m_arrDomain[nIndex][0] = 0;
|
|
m_arrDomain[nIndex][1] = 1;
|
|
}
|
|
m_bHasRange = false;
|
|
}
|
|
|
|
IdentityFunction::~IdentityFunction()
|
|
{
|
|
}
|
|
|
|
void IdentityFunction::Transform(double *pInput, double *pOutput)
|
|
{
|
|
for (int nIndex = 0; nIndex < funcMaxOutputs; ++nIndex)
|
|
{
|
|
pOutput[nIndex] = pInput[nIndex]; // òîæäåñòâåííàÿ æå ôóíêöèÿ :)
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
// SampledFunction
|
|
//------------------------------------------------------------------------
|
|
|
|
SampledFunction::SampledFunction(Object *pFuncObject, Dict *pDict)
|
|
{
|
|
m_pSamples = NULL;
|
|
m_pBuffer = NULL;
|
|
m_bValid = false;
|
|
|
|
if (!Initialize(pDict))
|
|
{
|
|
return;
|
|
}
|
|
if (!m_bHasRange)
|
|
{
|
|
// TO DO: Error "Type 0 function is missing range"
|
|
return;
|
|
}
|
|
if (m_nInputDim > sampledFuncMaxInputs)
|
|
{
|
|
// TO DO: Error "Sampled functions with more than sampledFuncMaxInputs inputs are unsupported"
|
|
return;
|
|
}
|
|
|
|
m_pBuffer = (double *)MemUtilsMallocArray(1 << m_nInputDim, sizeof(double));
|
|
|
|
if (!pFuncObject->IsStream())
|
|
{
|
|
// TO DO: Error "Type 0 function isn't a stream"
|
|
return;
|
|
}
|
|
Stream *pStream = pFuncObject->GetStream();
|
|
|
|
// Size
|
|
Object oArray;
|
|
if (!pDict->Search("Size", &oArray)->IsArray() || oArray.ArrayGetLength() != m_nInputDim)
|
|
{
|
|
// TO DO: Error "Function has missing or invalid size array"
|
|
oArray.Free();
|
|
return;
|
|
}
|
|
for (int nIndex = 0; nIndex < m_nInputDim; ++nIndex)
|
|
{
|
|
Object oTemp;
|
|
oArray.ArrayGet(nIndex, &oTemp);
|
|
if (!oTemp.IsInt())
|
|
{
|
|
// TO DO: Error "Illegal value in function size array"
|
|
oTemp.Free();
|
|
oArray.Free();
|
|
return;
|
|
}
|
|
m_arrSize[nIndex] = oTemp.GetInt();
|
|
oTemp.Free();
|
|
}
|
|
oArray.Free();
|
|
|
|
m_arrIndexMult[0] = m_nOutputDim;
|
|
for (int nIndex = 1; nIndex < m_nInputDim; ++nIndex)
|
|
{
|
|
m_arrIndexMult[nIndex] = m_arrIndexMult[nIndex - 1] * m_arrSize[nIndex - 1];
|
|
}
|
|
|
|
// BitsPerSample
|
|
if (!pDict->Search("BitsPerSample", &oArray)->IsInt())
|
|
{
|
|
// TO DO: Error "Function has missing or invalid BitsPerSample"
|
|
oArray.Free();
|
|
return;
|
|
}
|
|
int nSampleBits = oArray.GetInt();
|
|
double dSampleMult = 1.0 / (pow(2.0, (double)nSampleBits) - 1);
|
|
oArray.Free();
|
|
|
|
// TO DO: Ñäåëàòü ÷òåíèå ïîëÿ Order, è ðåàëèçîâàòü ôóíêöèþ Transform
|
|
|
|
// Encode
|
|
if (pDict->Search("Encode", &oArray)->IsArray() && oArray.ArrayGetLength() == 2 * m_nInputDim)
|
|
{
|
|
for (int nIndex = 0; nIndex < m_nInputDim; ++nIndex)
|
|
{
|
|
Object oTemp;
|
|
oArray.ArrayGet(2 * nIndex, &oTemp);
|
|
if (!oTemp.IsNum())
|
|
{
|
|
// TO DO: Error "Illegal value in function encode array"
|
|
oTemp.Free();
|
|
oArray.Free();
|
|
return;
|
|
}
|
|
m_arrEncoder[nIndex][0] = oTemp.GetNum();
|
|
oTemp.Free();
|
|
|
|
oArray.ArrayGet(2 * nIndex + 1, &oTemp);
|
|
if (!oTemp.IsNum())
|
|
{
|
|
// TO DO: Error "Illegal value in function encode array"
|
|
oTemp.Free();
|
|
oArray.Free();
|
|
return;
|
|
}
|
|
m_arrEncoder[nIndex][1] = oTemp.GetNum();
|
|
oTemp.Free();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (int nIndex = 0; nIndex < m_nInputDim; ++nIndex)
|
|
{
|
|
m_arrEncoder[nIndex][0] = 0;
|
|
m_arrEncoder[nIndex][1] = m_arrSize[nIndex] - 1;
|
|
}
|
|
}
|
|
oArray.Free();
|
|
|
|
for (int nIndex = 0; nIndex < m_nInputDim; ++nIndex)
|
|
{
|
|
m_arrInputMult[nIndex] = (m_arrEncoder[nIndex][1] - m_arrEncoder[nIndex][0]) / (m_arrDomain[nIndex][1] - m_arrDomain[nIndex][0]);
|
|
}
|
|
|
|
// Decode
|
|
if (pDict->Search("Decode", &oArray)->IsArray() && oArray.ArrayGetLength() == 2 * m_nOutputDim)
|
|
{
|
|
for (int nIndex = 0; nIndex < m_nOutputDim; ++nIndex)
|
|
{
|
|
Object oTemp;
|
|
oArray.ArrayGet(2 * nIndex, &oTemp);
|
|
if (!oTemp.IsNum())
|
|
{
|
|
// TO DO: Error "Illegal value in function decode array"
|
|
oTemp.Free();
|
|
oArray.Free();
|
|
return;
|
|
}
|
|
m_arrDecoder[nIndex][0] = oTemp.GetNum();
|
|
oTemp.Free();
|
|
|
|
oArray.ArrayGet(2 * nIndex + 1, &oTemp);
|
|
if (!oTemp.IsNum())
|
|
{
|
|
// TO DO: Error "Illegal value in function decode array"
|
|
oTemp.Free();
|
|
oArray.Free();
|
|
return;
|
|
}
|
|
m_arrDecoder[nIndex][1] = oTemp.GetNum();
|
|
oTemp.Free();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (int nIndex = 0; nIndex < m_nOutputDim; ++nIndex)
|
|
{
|
|
m_arrDecoder[nIndex][0] = m_arrRange[nIndex][0];
|
|
m_arrDecoder[nIndex][1] = m_arrRange[nIndex][1];
|
|
}
|
|
}
|
|
oArray.Free();
|
|
|
|
// Samples
|
|
m_nSamplesCount = m_nOutputDim;
|
|
for (int nIndex = 0; nIndex < m_nInputDim; ++nIndex)
|
|
m_nSamplesCount *= m_arrSize[nIndex];
|
|
m_pSamples = (double *)MemUtilsMallocArray(m_nSamplesCount, sizeof(double));
|
|
|
|
unsigned int unBuf = 0;
|
|
int nBitsCount = 0;
|
|
unsigned int unBitMask = (1 << nSampleBits) - 1;
|
|
pStream->Reset();
|
|
for (int nIndex = 0; nIndex < m_nSamplesCount; ++nIndex)
|
|
{
|
|
unsigned int unValue = 0;
|
|
if (nSampleBits == 8)
|
|
{
|
|
unValue = pStream->GetChar();
|
|
}
|
|
else if (nSampleBits == 16)
|
|
{
|
|
unValue = pStream->GetChar();
|
|
unValue = (unValue << 8) + pStream->GetChar();
|
|
}
|
|
else if (nSampleBits == 32)
|
|
{
|
|
unValue = pStream->GetChar();
|
|
unValue = (unValue << 8) + pStream->GetChar();
|
|
unValue = (unValue << 8) + pStream->GetChar();
|
|
unValue = (unValue << 8) + pStream->GetChar();
|
|
}
|
|
else
|
|
{
|
|
while (nBitsCount < nSampleBits)
|
|
{
|
|
unBuf = (unBuf << 8) | (pStream->GetChar() & 0xff);
|
|
nBitsCount += 8;
|
|
}
|
|
unValue = (unBuf >> (nBitsCount - nSampleBits)) & unBitMask;
|
|
nBitsCount -= nSampleBits;
|
|
}
|
|
m_pSamples[nIndex] = (double)unValue * dSampleMult;
|
|
}
|
|
pStream->Close();
|
|
|
|
m_bValid = true;
|
|
return;
|
|
}
|
|
|
|
SampledFunction::~SampledFunction()
|
|
{
|
|
MemUtilsFree(m_pSamples);
|
|
MemUtilsFree(m_pBuffer);
|
|
}
|
|
|
|
SampledFunction::SampledFunction(SampledFunction *pFunc)
|
|
{
|
|
memcpy(this, pFunc, sizeof(SampledFunction));
|
|
m_pSamples = (double *)MemUtilsMallocArray(m_nSamplesCount, sizeof(double));
|
|
memcpy(m_pSamples, pFunc->m_pSamples, m_nSamplesCount * sizeof(double));
|
|
m_pBuffer = (double *)MemUtilsMallocArray(1 << m_nInputDim, sizeof(double));
|
|
}
|
|
|
|
void SampledFunction::Transform(double *pInput, double *pOutput)
|
|
{
|
|
int arrE[funcMaxInputs][2];
|
|
double arrEFrac0[funcMaxInputs];
|
|
double arrEFrac1[funcMaxInputs];
|
|
|
|
for (int nIndex = 0; nIndex < m_nInputDim; ++nIndex)
|
|
{
|
|
double dValue = (pInput[nIndex] - m_arrDomain[nIndex][0]) * m_arrInputMult[nIndex] + m_arrEncoder[nIndex][0];
|
|
if (dValue < 0)
|
|
{
|
|
dValue = 0;
|
|
}
|
|
else if (dValue > m_arrSize[nIndex] - 1)
|
|
{
|
|
dValue = m_arrSize[nIndex] - 1;
|
|
}
|
|
arrE[nIndex][0] = (int)dValue;
|
|
if ((arrE[nIndex][1] = arrE[nIndex][0] + 1) >= m_arrSize[nIndex])
|
|
{
|
|
arrE[nIndex][1] = arrE[nIndex][0];
|
|
}
|
|
arrEFrac1[nIndex] = dValue - arrE[nIndex][0];
|
|
arrEFrac0[nIndex] = 1 - arrEFrac1[nIndex];
|
|
}
|
|
|
|
for (int nI = 0; nI < m_nOutputDim; ++nI)
|
|
{
|
|
for (int nJ = 0; nJ < (1 << m_nInputDim); ++nJ)
|
|
{
|
|
int nIdx = nI;
|
|
for (int nK = 0, t = nJ; nK < m_nInputDim; ++nK, t >>= 1)
|
|
{
|
|
nIdx += m_arrIndexMult[nK] * (arrE[nK][t & 1]);
|
|
}
|
|
m_pBuffer[nJ] = m_pSamples[nIdx];
|
|
}
|
|
|
|
int nT = 0;
|
|
for (int nJ = 0, nT = (1 << m_nInputDim); nJ < m_nInputDim; ++nJ, nT >>= 1)
|
|
{
|
|
for (int nK = 0; nK < nT; nK += 2)
|
|
{
|
|
m_pBuffer[nK >> 1] = arrEFrac0[nJ] * m_pBuffer[nK] + arrEFrac1[nJ] * m_pBuffer[nK + 1];
|
|
}
|
|
}
|
|
|
|
pOutput[nI] = m_pBuffer[0] * (m_arrDecoder[nI][1] - m_arrDecoder[nI][0]) + m_arrDecoder[nI][0];
|
|
if (pOutput[nI] < m_arrRange[nI][0])
|
|
{
|
|
pOutput[nI] = m_arrRange[nI][0];
|
|
}
|
|
else if (pOutput[nI] > m_arrRange[nI][1])
|
|
{
|
|
pOutput[nI] = m_arrRange[nI][1];
|
|
}
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
// ExponentialFunction
|
|
//------------------------------------------------------------------------
|
|
|
|
ExponentialFunction::ExponentialFunction(Object *pFuncObject, Dict *pDict)
|
|
{
|
|
m_bValid = false;
|
|
|
|
if (!Initialize(pDict))
|
|
{
|
|
return;
|
|
}
|
|
if (m_nInputDim != 1)
|
|
{
|
|
// TO DO: Error "Exponential function with more than one input"
|
|
return;
|
|
}
|
|
|
|
// C0
|
|
Object oArray;
|
|
if (pDict->Search("C0", &oArray)->IsArray())
|
|
{
|
|
if (m_bHasRange && oArray.ArrayGetLength() != m_nOutputDim)
|
|
{
|
|
// TO DO: Error "Function's C0 array is wrong length"
|
|
oArray.Free();
|
|
return;
|
|
}
|
|
m_nOutputDim = oArray.ArrayGetLength();
|
|
for (int nIndex = 0; nIndex < m_nOutputDim; ++nIndex)
|
|
{
|
|
Object oTemp;
|
|
oArray.ArrayGet(nIndex, &oTemp);
|
|
if (!oTemp.IsNum())
|
|
{
|
|
// TO DO: Error "Illegal value in function C0 array"
|
|
oArray.Free();
|
|
oTemp.Free();
|
|
return;
|
|
}
|
|
m_arrC0[nIndex] = oTemp.GetNum();
|
|
oTemp.Free();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (m_bHasRange && m_nOutputDim != 1)
|
|
{
|
|
// TO DO: Error "Function's C0 array is wrong length"
|
|
oArray.Free();
|
|
return;
|
|
}
|
|
m_nOutputDim = 1;
|
|
m_arrC0[0] = 0;
|
|
}
|
|
oArray.Free();
|
|
|
|
// C1
|
|
if (pDict->Search("C1", &oArray)->IsArray())
|
|
{
|
|
if (oArray.ArrayGetLength() != m_nOutputDim)
|
|
{
|
|
// TO DO: Error "Function's C1 array is wrong length"
|
|
oArray.Free();
|
|
return;
|
|
}
|
|
for (int nIndex = 0; nIndex < m_nOutputDim; ++nIndex)
|
|
{
|
|
Object oTemp;
|
|
oArray.ArrayGet(nIndex, &oTemp);
|
|
if (!oTemp.IsNum())
|
|
{
|
|
// TO DO: Error "Illegal value in function C1 array"
|
|
oTemp.Free();
|
|
oArray.Free();
|
|
return;
|
|
}
|
|
m_arrC1[nIndex] = oTemp.GetNum();
|
|
oTemp.Free();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (m_nOutputDim != 1)
|
|
{
|
|
// TO DO: Error "Function's C1 array is wrong length"
|
|
oArray.Free();
|
|
return;
|
|
}
|
|
m_arrC1[0] = 1;
|
|
}
|
|
oArray.Free();
|
|
|
|
// N (exponent)
|
|
if (!pDict->Search("N", &oArray)->IsNum())
|
|
{
|
|
// TO DO: Error "Function has missing or invalid N"
|
|
oArray.Free();
|
|
return;
|
|
}
|
|
m_dN = oArray.GetNum();
|
|
oArray.Free();
|
|
|
|
m_bValid = true;
|
|
return;
|
|
}
|
|
|
|
ExponentialFunction::~ExponentialFunction()
|
|
{
|
|
}
|
|
|
|
ExponentialFunction::ExponentialFunction(ExponentialFunction *pFunc)
|
|
{
|
|
memcpy(this, pFunc, sizeof(ExponentialFunction));
|
|
}
|
|
|
|
void ExponentialFunction::Transform(double *pInput, double *pOutput)
|
|
{
|
|
double dX = 0;
|
|
|
|
if (pInput[0] < m_arrDomain[0][0])
|
|
{
|
|
dX = m_arrDomain[0][0];
|
|
}
|
|
else if (pInput[0] > m_arrDomain[0][1])
|
|
{
|
|
dX = m_arrDomain[0][1];
|
|
}
|
|
else
|
|
{
|
|
dX = pInput[0];
|
|
}
|
|
for (int nIndex = 0; nIndex < m_nOutputDim; ++nIndex)
|
|
{
|
|
pOutput[nIndex] = m_arrC0[nIndex] + pow(dX, m_dN) * (m_arrC1[nIndex] - m_arrC0[nIndex]);
|
|
if (m_bHasRange)
|
|
{
|
|
if (pOutput[nIndex] < m_arrRange[nIndex][0])
|
|
{
|
|
pOutput[nIndex] = m_arrRange[nIndex][0];
|
|
}
|
|
else if (pOutput[nIndex] > m_arrRange[nIndex][1])
|
|
{
|
|
pOutput[nIndex] = m_arrRange[nIndex][1];
|
|
}
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
// StitchingFunction
|
|
//------------------------------------------------------------------------
|
|
|
|
StitchingFunction::StitchingFunction(Object *pFuncObject, Dict *pDict)
|
|
{
|
|
m_bValid = false;
|
|
m_ppFuncs = NULL;
|
|
m_arrBounds = NULL;
|
|
m_arrEncode = NULL;
|
|
m_arrScale = NULL;
|
|
|
|
if (!Initialize(pDict))
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (m_nInputDim != 1)
|
|
{
|
|
// TO DO: Error "Stitching function with more than one input"
|
|
return;
|
|
}
|
|
|
|
// Functions
|
|
Object oArray;
|
|
if (!pDict->Search("Functions", &oArray)->IsArray())
|
|
{
|
|
// TO DO: Error "Missing 'Functions' entry in stitching function"
|
|
oArray.Free();
|
|
return;
|
|
}
|
|
|
|
m_nCount = oArray.ArrayGetLength();
|
|
m_ppFuncs = (Function**)MemUtilsMallocArray(m_nCount, sizeof(Function *));
|
|
m_arrBounds = (double *)MemUtilsMallocArray(m_nCount + 1, sizeof(double));
|
|
m_arrEncode = (double *)MemUtilsMallocArray(2 * m_nCount, sizeof(double));
|
|
m_arrScale = (double *)MemUtilsMallocArray(m_nCount, sizeof(double));
|
|
|
|
for (int nIndex = 0; nIndex < m_nCount; ++nIndex)
|
|
{
|
|
m_ppFuncs[nIndex] = NULL;
|
|
}
|
|
|
|
for (int nIndex = 0; nIndex < m_nCount; ++nIndex)
|
|
{
|
|
Object oTemp;
|
|
if (!(m_ppFuncs[nIndex] = Function::Parse(oArray.ArrayGet(nIndex, &oTemp))))
|
|
{
|
|
oTemp.Free();
|
|
oArray.Free();
|
|
return;
|
|
}
|
|
|
|
if (nIndex > 0 && (m_ppFuncs[nIndex]->GetInputSize() != 1 || m_ppFuncs[nIndex]->GetOutputSize() != m_ppFuncs[0]->GetOutputSize()))
|
|
{
|
|
// TO DO: Error "Incompatible subfunctions in stitching function"
|
|
oTemp.Free();
|
|
oArray.Free();
|
|
return;
|
|
}
|
|
oTemp.Free();
|
|
}
|
|
oArray.Free();
|
|
|
|
// Bounds
|
|
if (!pDict->Search("Bounds", &oArray)->IsArray() || oArray.ArrayGetLength() != m_nCount - 1)
|
|
{
|
|
// TO DO: Error "Missing or invalid 'Bounds' entry in stitching function"
|
|
oArray.Free();
|
|
return;
|
|
}
|
|
m_arrBounds[0] = m_arrDomain[0][0];
|
|
for (int nIndex = 1; nIndex < m_nCount; ++nIndex)
|
|
{
|
|
Object oTemp;
|
|
if (!oArray.ArrayGet(nIndex - 1, &oTemp)->IsNum())
|
|
{
|
|
// TO DO: Error "Invalid type in 'Bounds' array in stitching function"
|
|
oTemp.Free();
|
|
oArray.Free();
|
|
return;
|
|
}
|
|
m_arrBounds[nIndex] = oTemp.GetNum();
|
|
oTemp.Free();
|
|
}
|
|
m_arrBounds[m_nCount] = m_arrDomain[0][1];
|
|
oArray.Free();
|
|
|
|
// Encode
|
|
if (!pDict->Search("Encode", &oArray)->IsArray() || oArray.ArrayGetLength() != 2 * m_nCount)
|
|
{
|
|
// TO DO: Error "Missing or invalid 'Encode' entry in stitching function"
|
|
oArray.Free();
|
|
return;
|
|
}
|
|
|
|
for (int nIndex = 0; nIndex < 2 * m_nCount; ++nIndex)
|
|
{
|
|
Object oTemp;
|
|
if (!oArray.ArrayGet(nIndex, &oTemp)->IsNum())
|
|
{
|
|
// TO DO: Error "Invalid type in 'Encode' array in stitching function"
|
|
oTemp.Free();
|
|
oArray.Free();
|
|
return;
|
|
}
|
|
m_arrEncode[nIndex] = oTemp.GetNum();
|
|
oTemp.Free();
|
|
}
|
|
oArray.Free();
|
|
|
|
for (int nIndex = 0; nIndex < m_nCount; ++nIndex)
|
|
{
|
|
if (m_arrBounds[nIndex] == m_arrBounds[nIndex + 1])
|
|
{
|
|
// ×òîáû èçáåæàòü äåëåíèå íà 0, â äàííîì ñëó÷àå ôóíêöèÿ ñ íîìåðîì nIndex íå áóäåò èñïîëüçîâàòüñÿ
|
|
m_arrScale[nIndex] = 0;
|
|
}
|
|
else
|
|
{
|
|
m_arrScale[nIndex] = (m_arrEncode[2 * nIndex + 1] - m_arrEncode[2 * nIndex]) / (m_arrBounds[nIndex + 1] - m_arrBounds[nIndex]);
|
|
}
|
|
}
|
|
|
|
m_bValid = true;
|
|
return;
|
|
}
|
|
|
|
StitchingFunction::StitchingFunction(StitchingFunction *pFunc)
|
|
{
|
|
m_nCount = pFunc->m_nCount;
|
|
m_ppFuncs = (Function **)MemUtilsMallocArray(m_nCount, sizeof(Function *));
|
|
|
|
for (int nIndex = 0; nIndex < m_nCount; ++nIndex)
|
|
{
|
|
m_ppFuncs[nIndex] = pFunc->m_ppFuncs[nIndex]->Copy();
|
|
}
|
|
|
|
m_arrBounds = (double *)MemUtilsMallocArray(m_nCount + 1, sizeof(double));
|
|
memcpy(m_arrBounds, pFunc->m_arrBounds, (m_nCount + 1) * sizeof(double));
|
|
|
|
m_arrEncode = (double *)MemUtilsMallocArray(2 * m_nCount, sizeof(double));
|
|
memcpy(m_arrEncode, pFunc->m_arrEncode, 2 * m_nCount * sizeof(double));
|
|
|
|
m_arrScale = (double *)MemUtilsMallocArray(m_nCount, sizeof(double));
|
|
memcpy(m_arrScale, pFunc->m_arrScale, m_nCount * sizeof(double));
|
|
|
|
m_bValid = true;
|
|
}
|
|
|
|
StitchingFunction::~StitchingFunction()
|
|
{
|
|
if (m_ppFuncs)
|
|
{
|
|
for (int nIndex = 0; nIndex < m_nCount; ++nIndex)
|
|
{
|
|
delete m_ppFuncs[nIndex];
|
|
}
|
|
}
|
|
MemUtilsFree(m_ppFuncs);
|
|
MemUtilsFree(m_arrBounds);
|
|
MemUtilsFree(m_arrEncode);
|
|
MemUtilsFree(m_arrScale);
|
|
}
|
|
|
|
void StitchingFunction::Transform(double *pInput, double *pOutput)
|
|
{
|
|
double dX;
|
|
|
|
if (pInput[0] < m_arrDomain[0][0])
|
|
{
|
|
dX = m_arrDomain[0][0];
|
|
}
|
|
else if (pInput[0] > m_arrDomain[0][1])
|
|
{
|
|
dX = m_arrDomain[0][1];
|
|
}
|
|
else
|
|
{
|
|
dX = pInput[0];
|
|
}
|
|
|
|
int nIndex = 0;
|
|
for (nIndex = 0; nIndex < m_nCount - 1; ++nIndex)
|
|
{
|
|
if (dX < m_arrBounds[nIndex + 1])
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
dX = m_arrEncode[2 * nIndex] + (dX - m_arrBounds[nIndex]) * m_arrScale[nIndex];
|
|
m_ppFuncs[nIndex]->Transform(&dX, pOutput);
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
// PostScriptFunction
|
|
//------------------------------------------------------------------------
|
|
|
|
enum PSOperations
|
|
{
|
|
psOperationAbs,
|
|
psOperationAdd,
|
|
psOperationAnd,
|
|
psOperationAtan,
|
|
psOperationBitshift,
|
|
psOperationCeiling,
|
|
psOperationCopy,
|
|
psOperationCos,
|
|
psOperationCvi,
|
|
psOperationCvr,
|
|
psOperationDiv,
|
|
psOperationDup,
|
|
psOperationEq,
|
|
psOperationExch,
|
|
psOperationExp,
|
|
psOperationFalse,
|
|
psOperationFloor,
|
|
psOperationGe,
|
|
psOperationGt,
|
|
psOperationIdiv,
|
|
psOperationIndex,
|
|
psOperationLe,
|
|
psOperationLn,
|
|
psOperationLog,
|
|
psOperationLt,
|
|
psOperationMod,
|
|
psOperationMul,
|
|
psOperationNe,
|
|
psOperationNeg,
|
|
psOperationNot,
|
|
psOperationOr,
|
|
psOperationPop,
|
|
psOperationRoll,
|
|
psOperationRound,
|
|
psOperationSin,
|
|
psOperationSqrt,
|
|
psOperationSub,
|
|
psOperationTrue,
|
|
psOperationTruncate,
|
|
psOperationXor,
|
|
psOperationIf,
|
|
psOperationIfelse,
|
|
psOperationReturn
|
|
};
|
|
|
|
// Ñïèñîê èäåò â àëôàâèòíîì ïîðÿäêå. Íîìåð ýëåìåíòà çäåñü, ñîîòâåòñòâóåò
|
|
// îïåðàöèè â ïåðå÷èñëÿåìîì òèïå PSOperations
|
|
char *c_sPSOperationNames[] =
|
|
{
|
|
"abs",
|
|
"add",
|
|
"and",
|
|
"atan",
|
|
"bitshift",
|
|
"ceiling",
|
|
"copy",
|
|
"cos",
|
|
"cvi",
|
|
"cvr",
|
|
"div",
|
|
"dup",
|
|
"eq",
|
|
"exch",
|
|
"exp",
|
|
"false",
|
|
"floor",
|
|
"ge",
|
|
"gt",
|
|
"idiv",
|
|
"index",
|
|
"le",
|
|
"ln",
|
|
"log",
|
|
"lt",
|
|
"mod",
|
|
"mul",
|
|
"ne",
|
|
"neg",
|
|
"not",
|
|
"or",
|
|
"pop",
|
|
"roll",
|
|
"round",
|
|
"sin",
|
|
"sqrt",
|
|
"sub",
|
|
"true",
|
|
"truncate",
|
|
"xor"
|
|
};
|
|
|
|
#define PSOperationsCount (sizeof(c_sPSOperationNames) / sizeof(char *))
|
|
|
|
enum PSObjectType
|
|
{
|
|
psBool,
|
|
psInt,
|
|
psReal,
|
|
psOperator,
|
|
psBlock
|
|
};
|
|
|
|
// Â ïîòîêå, îïåðàòîðû 'if'/'ifelse' çàíèìàþò òðè ñëîòà.
|
|
//
|
|
// +---------------------------------+
|
|
// | psOperator: If / Ifelse |
|
|
// +---------------------------------+
|
|
// | psBlock: óêàçàòåëü = <A> |
|
|
// +---------------------------------+
|
|
// | psBlock: óêàçàòåëü = <B> |
|
|
// +---------------------------------+
|
|
// | if |
|
|
// | ... |
|
|
// | psOperator: Return |
|
|
// +---------------------------------+
|
|
// <A> | else |
|
|
// | ... |
|
|
// | psOperator: Return |
|
|
// +---------------------------------+
|
|
// <B> | ... |
|
|
//
|
|
// Åñëè îïåðàòîð = 'if', óêàçàòåëü <A> âñå çàäàí, íî íå èñïîëüçóåòñÿ
|
|
|
|
struct PSObject
|
|
{
|
|
PSObjectType eType;
|
|
union
|
|
{
|
|
bool uBool; // boolean (stack only)
|
|
int uInt; // integer (stack and code)
|
|
double uReal; // real (stack and code)
|
|
PSOperations uOperation; // operator (code only)
|
|
int uBlock; // if/ifelse block pointer (code only)
|
|
};
|
|
};
|
|
|
|
#define psStackSize 100
|
|
|
|
class PSStack
|
|
{
|
|
public:
|
|
|
|
PSStack()
|
|
{
|
|
m_nStackSize = psStackSize;
|
|
}
|
|
void PushBool(bool bBool)
|
|
{
|
|
if (CheckOverflow())
|
|
{
|
|
m_arrStack[--m_nStackSize].eType = psBool;
|
|
m_arrStack[m_nStackSize].uBool = bBool;
|
|
}
|
|
}
|
|
|
|
void PushInt(int nInteger)
|
|
{
|
|
if (CheckOverflow())
|
|
{
|
|
m_arrStack[--m_nStackSize].eType = psInt;
|
|
m_arrStack[m_nStackSize].uInt = nInteger;
|
|
}
|
|
}
|
|
|
|
void PushReal(double dReal)
|
|
{
|
|
if (CheckOverflow())
|
|
{
|
|
m_arrStack[--m_nStackSize].eType = psReal;
|
|
m_arrStack[m_nStackSize].uReal = dReal;
|
|
}
|
|
}
|
|
|
|
bool PopBool()
|
|
{
|
|
if (CheckUnderflow() && CheckType(psBool, psBool))
|
|
{
|
|
return m_arrStack[m_nStackSize++].uBool;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
int PopInt()
|
|
{
|
|
if (CheckUnderflow() && CheckType(psInt, psInt))
|
|
{
|
|
return m_arrStack[m_nStackSize++].uInt;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
double PopNum()
|
|
{
|
|
if (CheckUnderflow() && CheckType(psInt, psReal))
|
|
{
|
|
double dReturn = (m_arrStack[m_nStackSize].eType == psInt) ? (double)m_arrStack[m_nStackSize].uInt : m_arrStack[m_nStackSize].uReal;
|
|
++m_nStackSize;
|
|
return dReturn;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
bool Empty()
|
|
{
|
|
return m_nStackSize == psStackSize;
|
|
}
|
|
bool TopIsInt()
|
|
{
|
|
return m_nStackSize < psStackSize && m_arrStack[m_nStackSize].eType == psInt;
|
|
}
|
|
bool TopTwoAreInts()
|
|
{
|
|
return m_nStackSize < psStackSize - 1 && m_arrStack[m_nStackSize].eType == psInt && m_arrStack[m_nStackSize + 1].eType == psInt;
|
|
}
|
|
bool TopIsReal()
|
|
{
|
|
return m_nStackSize < psStackSize && m_arrStack[m_nStackSize].eType == psReal;
|
|
}
|
|
bool TopTwoAreNums()
|
|
{
|
|
return m_nStackSize < psStackSize - 1 && (m_arrStack[m_nStackSize].eType == psInt || m_arrStack[m_nStackSize].eType == psReal) && (m_arrStack[m_nStackSize + 1].eType == psInt || m_arrStack[m_nStackSize + 1].eType == psReal);
|
|
}
|
|
|
|
void Copy(int nCount)
|
|
{
|
|
if (m_nStackSize + nCount > psStackSize)
|
|
{
|
|
// TO DO: Error "Stack underflow in PostScript function"
|
|
return;
|
|
}
|
|
if (!CheckOverflow(nCount))
|
|
{
|
|
return;
|
|
}
|
|
for (int nIndex = m_nStackSize + nCount - 1; nIndex >= m_nStackSize; --nIndex)
|
|
{
|
|
m_arrStack[nIndex - nCount] = m_arrStack[nIndex];
|
|
}
|
|
m_nStackSize -= nCount;
|
|
}
|
|
|
|
void Roll(int n, int j)
|
|
{
|
|
int i, k;
|
|
|
|
if (j >= 0)
|
|
{
|
|
j %= n;
|
|
}
|
|
else
|
|
{
|
|
j = -j % n;
|
|
if (j != 0)
|
|
{
|
|
j = n - j;
|
|
}
|
|
}
|
|
if (n <= 0 || j == 0)
|
|
{
|
|
return;
|
|
}
|
|
for (i = 0; i < j; ++i)
|
|
{
|
|
PSObject oPSObject = m_arrStack[m_nStackSize];
|
|
for (k = m_nStackSize; k < m_nStackSize + n - 1; ++k)
|
|
{
|
|
m_arrStack[k] = m_arrStack[k + 1];
|
|
}
|
|
m_arrStack[m_nStackSize + n - 1] = oPSObject;
|
|
}
|
|
}
|
|
|
|
void Index(int nIndex)
|
|
{
|
|
if (!CheckOverflow())
|
|
{
|
|
return;
|
|
}
|
|
--m_nStackSize;
|
|
m_arrStack[m_nStackSize] = m_arrStack[m_nStackSize + 1 + nIndex];
|
|
}
|
|
|
|
void Pop()
|
|
{
|
|
if (!CheckUnderflow())
|
|
{
|
|
return;
|
|
}
|
|
++m_nStackSize;
|
|
}
|
|
|
|
|
|
private:
|
|
|
|
bool CheckOverflow(int nCount = 1)
|
|
{
|
|
if (m_nStackSize - nCount < 0)
|
|
{
|
|
// TO DO: Error "Stack overflow in PostScript function"
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool CheckUnderflow()
|
|
{
|
|
if (m_nStackSize == psStackSize)
|
|
{
|
|
// TO DO: Error "Stack underflow in PostScript function"
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool CheckType(PSObjectType eType1, PSObjectType eType2)
|
|
{
|
|
if (m_arrStack[m_nStackSize].eType != eType1 && m_arrStack[m_nStackSize].eType != eType2)
|
|
{
|
|
// TO DO: Error "Type mismatch in PostScript function"
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
private:
|
|
|
|
PSObject m_arrStack[psStackSize];
|
|
int m_nStackSize;
|
|
};
|
|
|
|
PostScriptFunction::PostScriptFunction(Object *pFuncObject, Dict *pDict)
|
|
{
|
|
m_pCode = NULL;
|
|
m_nCodeSize = 0;
|
|
m_bValid = false;
|
|
|
|
if (!Initialize(pDict))
|
|
{
|
|
return;
|
|
}
|
|
if (!m_bHasRange)
|
|
{
|
|
// TO DO: Error "Type 4 function is missing range"
|
|
return;
|
|
}
|
|
|
|
if (!pFuncObject->IsStream())
|
|
{
|
|
// TO DO: Error "Type 4 function isn't a stream"
|
|
return;
|
|
}
|
|
Stream *pStream = pFuncObject->GetStream();
|
|
|
|
//----- parse the function
|
|
m_seCodeString = new StringExt();
|
|
pStream->Reset();
|
|
|
|
StringExt *seToken;
|
|
if (!(seToken = GetToken(pStream)) || seToken->Compare("{"))
|
|
{
|
|
// TO DO: Error "Expected '{' at start of PostScript function"
|
|
MemUtilsFree(seToken);
|
|
pStream->Close();
|
|
return;
|
|
}
|
|
if (seToken)
|
|
delete seToken;
|
|
int nCodePos = 0;
|
|
if (!ParseCode(pStream, &nCodePos))
|
|
{
|
|
pStream->Close();
|
|
return;
|
|
}
|
|
pStream->Close();
|
|
|
|
m_bValid = true;
|
|
}
|
|
|
|
PostScriptFunction::PostScriptFunction(PostScriptFunction *pFunc)
|
|
{
|
|
memcpy(this, pFunc, sizeof(PostScriptFunction));
|
|
m_pCode = (PSObject *)MemUtilsMallocArray(m_nCodeSize, sizeof(PSObject));
|
|
memcpy(m_pCode, pFunc->m_pCode, m_nCodeSize * sizeof(PSObject));
|
|
m_seCodeString = pFunc->m_seCodeString->Copy();
|
|
}
|
|
|
|
PostScriptFunction::~PostScriptFunction()
|
|
{
|
|
MemUtilsFree(m_pCode);
|
|
if (m_seCodeString)
|
|
delete m_seCodeString;
|
|
}
|
|
|
|
void PostScriptFunction::Transform(double *pInput, double *pOutput)
|
|
{
|
|
PSStack *pStack = new PSStack();
|
|
if (!pStack)
|
|
return;
|
|
|
|
for (int nIndex = 0; nIndex < m_nInputDim; ++nIndex)
|
|
{
|
|
pStack->PushReal(pInput[nIndex]);
|
|
}
|
|
Exec(pStack, 0);
|
|
|
|
for (int nIndex = m_nOutputDim - 1; nIndex >= 0; --nIndex)
|
|
{
|
|
pOutput[nIndex] = pStack->PopNum();
|
|
if (pOutput[nIndex] < m_arrRange[nIndex][0])
|
|
{
|
|
pOutput[nIndex] = m_arrRange[nIndex][0];
|
|
}
|
|
else if (pOutput[nIndex] > m_arrRange[nIndex][1])
|
|
{
|
|
pOutput[nIndex] = m_arrRange[nIndex][1];
|
|
}
|
|
}
|
|
delete pStack;
|
|
}
|
|
|
|
bool PostScriptFunction::ParseCode(Stream *pStream, int *pnCodePos)
|
|
{
|
|
StringExt *seToken;
|
|
|
|
while (1)
|
|
{
|
|
if (!(seToken = GetToken(pStream)))
|
|
{
|
|
// TO DO: Error "Unexpected end of PostScript function stream"
|
|
return false;
|
|
}
|
|
if (!seToken)
|
|
return false;
|
|
|
|
char *pCurChar = seToken->GetBuffer();
|
|
|
|
if (isdigit(*pCurChar) || *pCurChar == '.' || *pCurChar == '-')
|
|
{
|
|
bool bReal = false;
|
|
for (++pCurChar; *pCurChar; ++pCurChar)
|
|
{
|
|
if (*pCurChar == '.')
|
|
{
|
|
bReal = true;
|
|
break;
|
|
}
|
|
}
|
|
ResizeCode(*pnCodePos);
|
|
if (bReal)
|
|
{
|
|
m_pCode[*pnCodePos].eType = psReal;
|
|
m_pCode[*pnCodePos].uReal = atof(seToken->GetBuffer());
|
|
}
|
|
else
|
|
{
|
|
m_pCode[*pnCodePos].eType = psInt;
|
|
m_pCode[*pnCodePos].uInt = atoi(seToken->GetBuffer());
|
|
}
|
|
++*pnCodePos;
|
|
delete seToken;
|
|
}
|
|
else if (!seToken->Compare("{"))
|
|
{
|
|
delete seToken;
|
|
int nOperatorPos = *pnCodePos;
|
|
int nElsePos = 0;
|
|
*pnCodePos += 3;
|
|
ResizeCode(nOperatorPos + 2);
|
|
if (!ParseCode(pStream, pnCodePos))
|
|
{
|
|
return false;
|
|
}
|
|
if (!(seToken = GetToken(pStream)))
|
|
{
|
|
// TO DO: Error "Unexpected end of PostScript function stream"
|
|
return false;
|
|
}
|
|
if (!seToken->Compare("{"))
|
|
{
|
|
nElsePos = *pnCodePos;
|
|
if (!ParseCode(pStream, pnCodePos))
|
|
{
|
|
return false;
|
|
}
|
|
delete seToken;
|
|
if (!(seToken = GetToken(pStream)))
|
|
{
|
|
// TO DO: Error "Unexpected end of PostScript function stream"
|
|
return false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
nElsePos = -1;
|
|
}
|
|
if (!seToken->Compare("if"))
|
|
{
|
|
if (nElsePos >= 0)
|
|
{
|
|
// TO DO: Error "Got 'if' operator with two blocks in PostScript function"
|
|
return false;
|
|
}
|
|
m_pCode[nOperatorPos].eType = psOperator;
|
|
m_pCode[nOperatorPos].uOperation = psOperationIf;
|
|
m_pCode[nOperatorPos + 2].eType = psBlock;
|
|
m_pCode[nOperatorPos + 2].uBlock = *pnCodePos;
|
|
}
|
|
else if (!seToken->Compare("ifelse"))
|
|
{
|
|
if (nElsePos < 0)
|
|
{
|
|
// TO DO: Error "Got 'ifelse' operator with one blocks in PostScript function"
|
|
return false;
|
|
}
|
|
m_pCode[nOperatorPos].eType = psOperator;
|
|
m_pCode[nOperatorPos].uOperation = psOperationIfelse;
|
|
m_pCode[nOperatorPos + 1].eType = psBlock;
|
|
m_pCode[nOperatorPos + 1].uBlock = nElsePos;
|
|
m_pCode[nOperatorPos + 2].eType = psBlock;
|
|
m_pCode[nOperatorPos + 2].uBlock = *pnCodePos;
|
|
}
|
|
else
|
|
{
|
|
// TO DO: Error "Expected if/ifelse operator in PostScript function"
|
|
delete seToken;
|
|
return false;
|
|
}
|
|
delete seToken;
|
|
}
|
|
else if (!seToken->Compare("}"))
|
|
{
|
|
delete seToken;
|
|
ResizeCode(*pnCodePos);
|
|
m_pCode[*pnCodePos].eType = psOperator;
|
|
m_pCode[*pnCodePos].uOperation = psOperationReturn;
|
|
++*pnCodePos;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
int nFirst = -1;
|
|
int nSecond = PSOperationsCount;
|
|
// invariant: psOpNames[a] < tok < psOpNames[b]
|
|
int nCompareRes = 0;
|
|
while (nSecond - nFirst > 1)
|
|
{
|
|
int nMiddle = (nFirst + nSecond) / 2;
|
|
nCompareRes = seToken->Compare(c_sPSOperationNames[nMiddle]);
|
|
if (nCompareRes > 0)
|
|
{
|
|
nFirst = nMiddle;
|
|
}
|
|
else if (nCompareRes < 0)
|
|
{
|
|
nSecond = nMiddle;
|
|
}
|
|
else
|
|
{
|
|
nFirst = nSecond = nMiddle;
|
|
}
|
|
}
|
|
if (nCompareRes != 0)
|
|
{
|
|
// TO DO: Error "Unknown operator in PostScript function"
|
|
delete seToken;
|
|
return false;
|
|
}
|
|
delete seToken;
|
|
ResizeCode(*pnCodePos);
|
|
m_pCode[*pnCodePos].eType = psOperator;
|
|
m_pCode[*pnCodePos].uOperation = (PSOperations)nFirst;
|
|
++*pnCodePos;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
StringExt *PostScriptFunction::GetToken(Stream *pStream)
|
|
{
|
|
int nChar = 0;
|
|
|
|
StringExt *seResult = new StringExt();
|
|
bool bComment = false;
|
|
|
|
while (1)
|
|
{
|
|
if ((nChar = pStream->GetChar()) == EOF)
|
|
{
|
|
break;
|
|
}
|
|
m_seCodeString->Append(nChar);
|
|
if (bComment)
|
|
{
|
|
if (nChar == '\x0a' || nChar == '\x0d')
|
|
{
|
|
bComment = false;
|
|
}
|
|
}
|
|
else if (nChar == '%')
|
|
{
|
|
bComment = true;
|
|
}
|
|
else if (!isspace(nChar))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
if (nChar == '{' || nChar == '}')
|
|
{
|
|
seResult->Append((char)nChar);
|
|
}
|
|
else if (isdigit(nChar) || nChar == '.' || nChar == '-')
|
|
{
|
|
while (1)
|
|
{
|
|
seResult->Append((char)nChar);
|
|
nChar = pStream->LookChar();
|
|
if (nChar == EOF || !(isdigit(nChar) || nChar == '.' || nChar == '-'))
|
|
{
|
|
break;
|
|
}
|
|
pStream->GetChar();
|
|
m_seCodeString->Append(nChar);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
while (1)
|
|
{
|
|
seResult->Append((char)nChar);
|
|
nChar = pStream->LookChar();
|
|
if (nChar == EOF || !isalnum(nChar))
|
|
{
|
|
break;
|
|
}
|
|
pStream->GetChar();
|
|
m_seCodeString->Append(nChar);
|
|
}
|
|
}
|
|
return seResult;
|
|
}
|
|
|
|
void PostScriptFunction::ResizeCode(int nNewSize)
|
|
{
|
|
if (nNewSize >= m_nCodeSize)
|
|
{
|
|
m_nCodeSize += 64;
|
|
m_pCode = (PSObject *)MemUtilsReallocArray(m_pCode, m_nCodeSize, sizeof(PSObject));
|
|
}
|
|
}
|
|
|
|
void PostScriptFunction::Exec(PSStack *pStack, int codePtr)
|
|
{
|
|
int nInteger1 = 0, nInteger2 = 0;
|
|
double dReal1 = 0, dReal2 = 0;
|
|
bool bBool1 = false, bBool2 = false;
|
|
|
|
while (1)
|
|
{
|
|
switch (m_pCode[codePtr].eType)
|
|
{
|
|
case psInt:
|
|
pStack->PushInt(m_pCode[codePtr++].uInt);
|
|
break;
|
|
case psReal:
|
|
pStack->PushReal(m_pCode[codePtr++].uReal);
|
|
break;
|
|
case psOperator:
|
|
switch (m_pCode[codePtr++].uOperation)
|
|
{
|
|
case psOperationAbs:
|
|
if (pStack->TopIsInt())
|
|
{
|
|
pStack->PushInt(abs(pStack->PopInt()));
|
|
}
|
|
else
|
|
{
|
|
pStack->PushReal(fabs(pStack->PopNum()));
|
|
}
|
|
break;
|
|
case psOperationAdd:
|
|
if (pStack->TopTwoAreInts())
|
|
{
|
|
nInteger2 = pStack->PopInt();
|
|
nInteger1 = pStack->PopInt();
|
|
pStack->PushInt(nInteger1 + nInteger2);
|
|
}
|
|
else
|
|
{
|
|
dReal2 = pStack->PopNum();
|
|
dReal1 = pStack->PopNum();
|
|
pStack->PushReal(dReal1 + dReal2);
|
|
}
|
|
break;
|
|
case psOperationAnd:
|
|
if (pStack->TopTwoAreInts())
|
|
{
|
|
nInteger2 = pStack->PopInt();
|
|
nInteger1 = pStack->PopInt();
|
|
pStack->PushInt(nInteger1 & nInteger2);
|
|
}
|
|
else
|
|
{
|
|
bBool2 = pStack->PopBool();
|
|
bBool1 = pStack->PopBool();
|
|
pStack->PushBool(bBool1 && bBool2);
|
|
}
|
|
break;
|
|
case psOperationAtan:
|
|
dReal2 = pStack->PopNum();
|
|
dReal1 = pStack->PopNum();
|
|
pStack->PushReal(atan2(dReal1, dReal2));
|
|
break;
|
|
case psOperationBitshift:
|
|
nInteger2 = pStack->PopInt();
|
|
nInteger1 = pStack->PopInt();
|
|
if (nInteger2 > 0)
|
|
{
|
|
pStack->PushInt(nInteger1 << nInteger2);
|
|
}
|
|
else if (nInteger2 < 0)
|
|
{
|
|
pStack->PushInt((int)((unsigned int)nInteger1 >> nInteger2));
|
|
}
|
|
else
|
|
{
|
|
pStack->PushInt(nInteger1);
|
|
}
|
|
break;
|
|
case psOperationCeiling:
|
|
if (!pStack->TopIsInt())
|
|
{
|
|
pStack->PushReal(ceil(pStack->PopNum()));
|
|
}
|
|
break;
|
|
case psOperationCopy:
|
|
pStack->Copy(pStack->PopInt());
|
|
break;
|
|
case psOperationCos:
|
|
pStack->PushReal(cos(pStack->PopNum()));
|
|
break;
|
|
case psOperationCvi:
|
|
if (!pStack->TopIsInt())
|
|
{
|
|
pStack->PushInt((int)pStack->PopNum());
|
|
}
|
|
break;
|
|
case psOperationCvr:
|
|
if (!pStack->TopIsReal())
|
|
{
|
|
pStack->PushReal(pStack->PopNum());
|
|
}
|
|
break;
|
|
case psOperationDiv:
|
|
dReal2 = pStack->PopNum();
|
|
dReal1 = pStack->PopNum();
|
|
pStack->PushReal(dReal1 / dReal2);
|
|
break;
|
|
case psOperationDup:
|
|
pStack->Copy(1);
|
|
break;
|
|
case psOperationEq:
|
|
if (pStack->TopTwoAreInts())
|
|
{
|
|
nInteger2 = pStack->PopInt();
|
|
nInteger1 = pStack->PopInt();
|
|
pStack->PushBool(nInteger1 == nInteger2);
|
|
}
|
|
else if (pStack->TopTwoAreNums())
|
|
{
|
|
dReal2 = pStack->PopNum();
|
|
dReal1 = pStack->PopNum();
|
|
pStack->PushBool(dReal1 == dReal2);
|
|
}
|
|
else
|
|
{
|
|
bBool2 = pStack->PopBool();
|
|
bBool1 = pStack->PopBool();
|
|
pStack->PushBool(bBool1 == bBool2);
|
|
}
|
|
break;
|
|
case psOperationExch:
|
|
pStack->Roll(2, 1);
|
|
break;
|
|
case psOperationExp:
|
|
dReal2 = pStack->PopNum();
|
|
dReal1 = pStack->PopNum();
|
|
pStack->PushReal(pow(dReal1, dReal2));
|
|
break;
|
|
case psOperationFalse:
|
|
pStack->PushBool(false);
|
|
break;
|
|
case psOperationFloor:
|
|
if (!pStack->TopIsInt())
|
|
{
|
|
pStack->PushReal(floor(pStack->PopNum()));
|
|
}
|
|
break;
|
|
case psOperationGe:
|
|
if (pStack->TopTwoAreInts())
|
|
{
|
|
nInteger2 = pStack->PopInt();
|
|
nInteger1 = pStack->PopInt();
|
|
pStack->PushBool(nInteger1 >= nInteger2);
|
|
}
|
|
else
|
|
{
|
|
dReal2 = pStack->PopNum();
|
|
dReal1 = pStack->PopNum();
|
|
pStack->PushBool(dReal1 >= dReal2);
|
|
}
|
|
break;
|
|
case psOperationGt:
|
|
if (pStack->TopTwoAreInts())
|
|
{
|
|
nInteger2 = pStack->PopInt();
|
|
nInteger1 = pStack->PopInt();
|
|
pStack->PushBool(nInteger1 > nInteger2);
|
|
}
|
|
else
|
|
{
|
|
dReal2 = pStack->PopNum();
|
|
dReal1 = pStack->PopNum();
|
|
pStack->PushBool(dReal1 > dReal2);
|
|
}
|
|
break;
|
|
case psOperationIdiv:
|
|
nInteger2 = pStack->PopInt();
|
|
nInteger1 = pStack->PopInt();
|
|
pStack->PushInt(nInteger1 / nInteger2);
|
|
break;
|
|
case psOperationIndex:
|
|
pStack->Index(pStack->PopInt());
|
|
break;
|
|
case psOperationLe:
|
|
if (pStack->TopTwoAreInts())
|
|
{
|
|
nInteger2 = pStack->PopInt();
|
|
nInteger1 = pStack->PopInt();
|
|
pStack->PushBool(nInteger1 <= nInteger2);
|
|
}
|
|
else
|
|
{
|
|
dReal2 = pStack->PopNum();
|
|
dReal1 = pStack->PopNum();
|
|
pStack->PushBool(dReal1 <= dReal2);
|
|
}
|
|
break;
|
|
case psOperationLn:
|
|
pStack->PushReal(log(pStack->PopNum()));
|
|
break;
|
|
case psOperationLog:
|
|
pStack->PushReal(log10(pStack->PopNum()));
|
|
break;
|
|
case psOperationLt:
|
|
if (pStack->TopTwoAreInts())
|
|
{
|
|
nInteger2 = pStack->PopInt();
|
|
nInteger1 = pStack->PopInt();
|
|
pStack->PushBool(nInteger1 < nInteger2);
|
|
}
|
|
else
|
|
{
|
|
dReal2 = pStack->PopNum();
|
|
dReal1 = pStack->PopNum();
|
|
pStack->PushBool(dReal1 < dReal2);
|
|
}
|
|
break;
|
|
case psOperationMod:
|
|
nInteger2 = pStack->PopInt();
|
|
nInteger1 = pStack->PopInt();
|
|
pStack->PushInt(nInteger1 % nInteger2);
|
|
break;
|
|
case psOperationMul:
|
|
if (pStack->TopTwoAreInts())
|
|
{
|
|
nInteger2 = pStack->PopInt();
|
|
nInteger1 = pStack->PopInt();
|
|
//~ should check for out-of-range, and push a real instead
|
|
pStack->PushInt(nInteger1 * nInteger2);
|
|
}
|
|
else
|
|
{
|
|
dReal2 = pStack->PopNum();
|
|
dReal1 = pStack->PopNum();
|
|
pStack->PushReal(dReal1 * dReal2);
|
|
}
|
|
break;
|
|
case psOperationNe:
|
|
if (pStack->TopTwoAreInts())
|
|
{
|
|
nInteger2 = pStack->PopInt();
|
|
nInteger1 = pStack->PopInt();
|
|
pStack->PushBool(nInteger1 != nInteger2);
|
|
}
|
|
else if (pStack->TopTwoAreNums())
|
|
{
|
|
dReal2 = pStack->PopNum();
|
|
dReal1 = pStack->PopNum();
|
|
pStack->PushBool(dReal1 != dReal2);
|
|
}
|
|
else
|
|
{
|
|
bBool2 = pStack->PopBool();
|
|
bBool1 = pStack->PopBool();
|
|
pStack->PushBool(bBool1 != bBool2);
|
|
}
|
|
break;
|
|
case psOperationNeg:
|
|
if (pStack->TopIsInt())
|
|
{
|
|
pStack->PushInt(-pStack->PopInt());
|
|
}
|
|
else
|
|
{
|
|
pStack->PushReal(-pStack->PopNum());
|
|
}
|
|
break;
|
|
case psOperationNot:
|
|
if (pStack->TopIsInt())
|
|
{
|
|
pStack->PushInt(~pStack->PopInt());
|
|
}
|
|
else
|
|
{
|
|
pStack->PushBool(!pStack->PopBool());
|
|
}
|
|
break;
|
|
case psOperationOr:
|
|
if (pStack->TopTwoAreInts())
|
|
{
|
|
nInteger2 = pStack->PopInt();
|
|
nInteger1 = pStack->PopInt();
|
|
pStack->PushInt(nInteger1 | nInteger2);
|
|
}
|
|
else
|
|
{
|
|
bBool2 = pStack->PopBool();
|
|
bBool1 = pStack->PopBool();
|
|
pStack->PushBool(bBool1 || bBool2);
|
|
}
|
|
break;
|
|
case psOperationPop:
|
|
pStack->Pop();
|
|
break;
|
|
case psOperationRoll:
|
|
nInteger2 = pStack->PopInt();
|
|
nInteger1 = pStack->PopInt();
|
|
pStack->Roll(nInteger1, nInteger2);
|
|
break;
|
|
case psOperationRound:
|
|
if (!pStack->TopIsInt())
|
|
{
|
|
dReal1 = pStack->PopNum();
|
|
pStack->PushReal((dReal1 >= 0) ? floor(dReal1 + 0.5) : ceil(dReal1 - 0.5));
|
|
}
|
|
break;
|
|
case psOperationSin:
|
|
pStack->PushReal(sin(pStack->PopNum()));
|
|
break;
|
|
case psOperationSqrt:
|
|
pStack->PushReal(sqrt(pStack->PopNum()));
|
|
break;
|
|
case psOperationSub:
|
|
if (pStack->TopTwoAreInts())
|
|
{
|
|
nInteger2 = pStack->PopInt();
|
|
nInteger1 = pStack->PopInt();
|
|
pStack->PushInt(nInteger1 - nInteger2);
|
|
}
|
|
else
|
|
{
|
|
dReal2 = pStack->PopNum();
|
|
dReal1 = pStack->PopNum();
|
|
pStack->PushReal(dReal1 - dReal2);
|
|
}
|
|
break;
|
|
case psOperationTrue:
|
|
pStack->PushBool(true);
|
|
break;
|
|
case psOperationTruncate:
|
|
if (!pStack->TopIsInt())
|
|
{
|
|
dReal1 = pStack->PopNum();
|
|
pStack->PushReal((dReal1 >= 0) ? floor(dReal1) : ceil(dReal1));
|
|
}
|
|
break;
|
|
case psOperationXor:
|
|
if (pStack->TopTwoAreInts())
|
|
{
|
|
nInteger2 = pStack->PopInt();
|
|
nInteger1 = pStack->PopInt();
|
|
pStack->PushInt(nInteger1 ^ nInteger2);
|
|
}
|
|
else
|
|
{
|
|
bBool2 = pStack->PopBool();
|
|
bBool1 = pStack->PopBool();
|
|
pStack->PushBool(bBool1 ^ bBool2);
|
|
}
|
|
break;
|
|
case psOperationIf:
|
|
bBool1 = pStack->PopBool();
|
|
if (bBool1)
|
|
{
|
|
Exec(pStack, codePtr + 2);
|
|
}
|
|
codePtr = m_pCode[codePtr + 1].uBlock;
|
|
break;
|
|
case psOperationIfelse:
|
|
bBool1 = pStack->PopBool();
|
|
if (bBool1)
|
|
{
|
|
Exec(pStack, codePtr + 2);
|
|
}
|
|
else
|
|
{
|
|
Exec(pStack, m_pCode[codePtr].uBlock);
|
|
}
|
|
codePtr = m_pCode[codePtr + 1].uBlock;
|
|
break;
|
|
case psOperationReturn:
|
|
return;
|
|
}
|
|
break;
|
|
default:
|
|
// TO DO: Error "Internal: bad object in PostScript function code"
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
} |