Files
core/ASCOfficePDFReader/Function.cpp

1867 lines
41 KiB
C++

#include "stdafx.h"
#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"
//------------------------------------------------------------------------
// 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;
}
}
}