Home | History | Annotate | Download | only in fpdf_page
      1 // Copyright 2014 PDFium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
      6 
      7 #include "../../../include/fpdfapi/fpdf_page.h"
      8 #include "../../../include/fpdfapi/fpdf_module.h"
      9 #include "pageint.h"
     10 #include <limits.h>
     11 class CPDF_PSEngine;
     12 typedef enum {PSOP_ADD, PSOP_SUB, PSOP_MUL, PSOP_DIV, PSOP_IDIV, PSOP_MOD,
     13               PSOP_NEG, PSOP_ABS, PSOP_CEILING, PSOP_FLOOR, PSOP_ROUND, PSOP_TRUNCATE,
     14               PSOP_SQRT, PSOP_SIN, PSOP_COS, PSOP_ATAN, PSOP_EXP, PSOP_LN, PSOP_LOG,
     15               PSOP_CVI, PSOP_CVR, PSOP_EQ, PSOP_NE, PSOP_GT, PSOP_GE, PSOP_LT, PSOP_LE,
     16               PSOP_AND, PSOP_OR, PSOP_XOR, PSOP_NOT, PSOP_BITSHIFT, PSOP_TRUE, PSOP_FALSE,
     17               PSOP_IF, PSOP_IFELSE, PSOP_POP, PSOP_EXCH, PSOP_DUP, PSOP_COPY,
     18               PSOP_INDEX, PSOP_ROLL, PSOP_PROC, PSOP_CONST
     19              } PDF_PSOP;
     20 class CPDF_PSProc : public CFX_Object
     21 {
     22 public:
     23     ~CPDF_PSProc();
     24     FX_BOOL	Parse(CPDF_SimpleParser& parser);
     25     FX_BOOL	Execute(CPDF_PSEngine* pEngine);
     26     CFX_PtrArray		m_Operators;
     27 };
     28 #define PSENGINE_STACKSIZE 100
     29 class CPDF_PSEngine : public CFX_Object
     30 {
     31 public:
     32     CPDF_PSEngine();
     33     ~CPDF_PSEngine();
     34     FX_BOOL	Parse(const FX_CHAR* string, int size);
     35     FX_BOOL	Execute()
     36     {
     37         return m_MainProc.Execute(this);
     38     }
     39     FX_BOOL	DoOperator(PDF_PSOP op);
     40     void	Reset()
     41     {
     42         m_StackCount = 0;
     43     }
     44     void	Push(FX_FLOAT value);
     45     void	Push(int value)
     46     {
     47         Push((FX_FLOAT)value);
     48     }
     49     FX_FLOAT	Pop();
     50     int		GetStackSize()
     51     {
     52         return m_StackCount;
     53     }
     54 private:
     55     FX_FLOAT	m_Stack[PSENGINE_STACKSIZE];
     56     int		m_StackCount;
     57     CPDF_PSProc	m_MainProc;
     58 };
     59 CPDF_PSProc::~CPDF_PSProc()
     60 {
     61     int size = m_Operators.GetSize();
     62     for (int i = 0; i < size; i ++) {
     63         if (m_Operators[i] == (FX_LPVOID)PSOP_PROC) {
     64             delete (CPDF_PSProc*)m_Operators[i + 1];
     65             i ++;
     66         } else if (m_Operators[i] == (FX_LPVOID)PSOP_CONST) {
     67             FX_Free((FX_FLOAT*)m_Operators[i + 1]);
     68             i ++;
     69         }
     70     }
     71 }
     72 #pragma optimize( "", off )
     73 FX_BOOL CPDF_PSProc::Execute(CPDF_PSEngine* pEngine)
     74 {
     75     int size = m_Operators.GetSize();
     76     for (int i = 0; i < size; i ++) {
     77         PDF_PSOP op = (PDF_PSOP)(FX_UINTPTR)m_Operators[i];
     78         if (op == PSOP_PROC) {
     79             i ++;
     80         } else if (op == PSOP_CONST) {
     81             pEngine->Push(*(FX_FLOAT*)m_Operators[i + 1]);
     82             i ++;
     83         } else if (op == PSOP_IF) {
     84             if (i < 2 || m_Operators[i - 2] != (FX_LPVOID)PSOP_PROC) {
     85                 return FALSE;
     86             }
     87             if ((int)pEngine->Pop()) {
     88                 ((CPDF_PSProc*)m_Operators[i - 1])->Execute(pEngine);
     89             }
     90         } else if (op == PSOP_IFELSE) {
     91             if (i < 4 || m_Operators[i - 2] != (FX_LPVOID)PSOP_PROC ||
     92                     m_Operators[i - 4] != (FX_LPVOID)PSOP_PROC) {
     93                 return FALSE;
     94             }
     95             if ((int)pEngine->Pop()) {
     96                 ((CPDF_PSProc*)m_Operators[i - 3])->Execute(pEngine);
     97             } else {
     98                 ((CPDF_PSProc*)m_Operators[i - 1])->Execute(pEngine);
     99             }
    100         } else {
    101             pEngine->DoOperator(op);
    102         }
    103     }
    104     return TRUE;
    105 }
    106 #pragma optimize( "", on )
    107 CPDF_PSEngine::CPDF_PSEngine()
    108 {
    109     m_StackCount = 0;
    110 }
    111 CPDF_PSEngine::~CPDF_PSEngine()
    112 {
    113 }
    114 void CPDF_PSEngine::Push(FX_FLOAT v)
    115 {
    116     if (m_StackCount == 100) {
    117         return;
    118     }
    119     m_Stack[m_StackCount++] = v;
    120 }
    121 FX_FLOAT CPDF_PSEngine::Pop()
    122 {
    123     if (m_StackCount == 0) {
    124         return 0;
    125     }
    126     return m_Stack[--m_StackCount];
    127 }
    128 const struct _PDF_PSOpName {
    129     const FX_CHAR* name;
    130     PDF_PSOP op;
    131 } _PDF_PSOpNames[] = {
    132     {"add", PSOP_ADD}, {"sub", PSOP_SUB}, {"mul", PSOP_MUL}, {"div", PSOP_DIV},
    133     {"idiv", PSOP_IDIV}, {"mod", PSOP_MOD}, {"neg", PSOP_NEG}, {"abs", PSOP_ABS},
    134     {"ceiling", PSOP_CEILING}, {"floor", PSOP_FLOOR}, {"round", PSOP_ROUND},
    135     {"truncate", PSOP_TRUNCATE}, {"sqrt", PSOP_SQRT}, {"sin", PSOP_SIN},
    136     {"cos", PSOP_COS}, {"atan", PSOP_ATAN}, {"exp", PSOP_EXP}, {"ln", PSOP_LN},
    137     {"log", PSOP_LOG}, {"cvi", PSOP_CVI}, {"cvr", PSOP_CVR}, {"eq", PSOP_EQ},
    138     {"ne", PSOP_NE}, {"gt", PSOP_GT}, {"ge", PSOP_GE}, {"lt", PSOP_LT},
    139     {"le", PSOP_LE}, {"and", PSOP_AND}, {"or", PSOP_OR}, {"xor", PSOP_XOR},
    140     {"not", PSOP_NOT}, {"bitshift", PSOP_BITSHIFT}, {"true", PSOP_TRUE},
    141     {"false", PSOP_FALSE}, {"if", PSOP_IF}, {"ifelse", PSOP_IFELSE},
    142     {"pop", PSOP_POP}, {"exch", PSOP_EXCH}, {"dup", PSOP_DUP},
    143     {"copy", PSOP_COPY}, {"index", PSOP_INDEX}, {"roll", PSOP_ROLL},
    144     {NULL, PSOP_PROC}
    145 };
    146 FX_BOOL CPDF_PSEngine::Parse(const FX_CHAR* string, int size)
    147 {
    148     CPDF_SimpleParser parser((FX_LPBYTE)string, size);
    149     CFX_ByteStringC word = parser.GetWord();
    150     if (word != FX_BSTRC("{")) {
    151         return FALSE;
    152     }
    153     return m_MainProc.Parse(parser);
    154 }
    155 FX_BOOL CPDF_PSProc::Parse(CPDF_SimpleParser& parser)
    156 {
    157     while (1) {
    158         CFX_ByteStringC word = parser.GetWord();
    159         if (word.IsEmpty()) {
    160             return FALSE;
    161         }
    162         if (word == FX_BSTRC("}")) {
    163             return TRUE;
    164         }
    165         if (word == FX_BSTRC("{")) {
    166             CPDF_PSProc* pProc = FX_NEW CPDF_PSProc;
    167             m_Operators.Add((FX_LPVOID)PSOP_PROC);
    168             m_Operators.Add(pProc);
    169             if (!pProc->Parse(parser)) {
    170                 return FALSE;
    171             }
    172         } else {
    173             int i = 0;
    174             while (_PDF_PSOpNames[i].name) {
    175                 if (word == CFX_ByteStringC(_PDF_PSOpNames[i].name)) {
    176                     m_Operators.Add((FX_LPVOID)_PDF_PSOpNames[i].op);
    177                     break;
    178                 }
    179                 i ++;
    180             }
    181             if (_PDF_PSOpNames[i].name == NULL) {
    182                 FX_FLOAT* pd = FX_Alloc(FX_FLOAT, 1);
    183                 *pd = FX_atof(word);
    184                 m_Operators.Add((FX_LPVOID)PSOP_CONST);
    185                 m_Operators.Add(pd);
    186             }
    187         }
    188     }
    189 }
    190 #define PI 3.1415926535897932384626433832795f
    191 FX_BOOL CPDF_PSEngine::DoOperator(PDF_PSOP op)
    192 {
    193     int i1, i2;
    194     FX_FLOAT d1, d2;
    195     switch (op) {
    196         case PSOP_ADD:
    197             d1 = Pop();
    198             d2 = Pop();
    199             Push(d1 + d2);
    200             break;
    201         case PSOP_SUB:
    202             d2 = Pop();
    203             d1 = Pop();
    204             Push(d1 - d2);
    205             break;
    206         case PSOP_MUL:
    207             d1 = Pop();
    208             d2 = Pop();
    209             Push(d1 * d2);
    210             break;
    211         case PSOP_DIV:
    212             d2 = Pop();
    213             d1 = Pop();
    214             Push(d1 / d2);
    215             break;
    216         case PSOP_IDIV:
    217             i2 = (int)Pop();
    218             i1 = (int)Pop();
    219             Push(i1 / i2);
    220             break;
    221         case PSOP_MOD:
    222             i2 = (int)Pop();
    223             i1 = (int)Pop();
    224             Push(i1 % i2);
    225             break;
    226         case PSOP_NEG:
    227             d1 = Pop();
    228             Push(-d1);
    229             break;
    230         case PSOP_ABS:
    231             d1 = Pop();
    232             Push((FX_FLOAT)FXSYS_fabs(d1));
    233             break;
    234         case PSOP_CEILING:
    235             d1 = Pop();
    236             Push((FX_FLOAT)FXSYS_ceil(d1));
    237             break;
    238         case PSOP_FLOOR:
    239             d1 = Pop();
    240             Push((FX_FLOAT)FXSYS_floor(d1));
    241             break;
    242         case PSOP_ROUND:
    243             d1 = Pop();
    244             Push(FXSYS_round(d1));
    245             break;
    246         case PSOP_TRUNCATE:
    247             i1 = (int)Pop();
    248             Push(i1);
    249             break;
    250         case PSOP_SQRT:
    251             d1 = Pop();
    252             Push((FX_FLOAT)FXSYS_sqrt(d1));
    253             break;
    254         case PSOP_SIN:
    255             d1 = Pop();
    256             Push((FX_FLOAT)FXSYS_sin(d1 * PI / 180.0f));
    257             break;
    258         case PSOP_COS:
    259             d1 = Pop();
    260             Push((FX_FLOAT)FXSYS_cos(d1 * PI / 180.0f));
    261             break;
    262         case PSOP_ATAN:
    263             d2 = Pop();
    264             d1 = Pop();
    265             d1 = (FX_FLOAT)(FXSYS_atan2(d1, d2) * 180.0 / PI);
    266             if (d1 < 0) {
    267                 d1 += 360;
    268             }
    269             Push(d1);
    270             break;
    271         case PSOP_EXP:
    272             d2 = Pop();
    273             d1 = Pop();
    274             Push((FX_FLOAT)FXSYS_pow(d1, d2));
    275             break;
    276         case PSOP_LN:
    277             d1 = Pop();
    278             Push((FX_FLOAT)FXSYS_log(d1));
    279             break;
    280         case PSOP_LOG:
    281             d1 = Pop();
    282             Push((FX_FLOAT)FXSYS_log10(d1));
    283             break;
    284         case PSOP_CVI:
    285             i1 = (int)Pop();
    286             Push(i1);
    287             break;
    288         case PSOP_CVR:
    289             break;
    290         case PSOP_EQ:
    291             d2 = Pop();
    292             d1 = Pop();
    293             Push((int)(d1 == d2));
    294             break;
    295         case PSOP_NE:
    296             d2 = Pop();
    297             d1 = Pop();
    298             Push((int)(d1 != d2));
    299             break;
    300         case PSOP_GT:
    301             d2 = Pop();
    302             d1 = Pop();
    303             Push((int)(d1 > d2));
    304             break;
    305         case PSOP_GE:
    306             d2 = Pop();
    307             d1 = Pop();
    308             Push((int)(d1 >= d2));
    309             break;
    310         case PSOP_LT:
    311             d2 = Pop();
    312             d1 = Pop();
    313             Push((int)(d1 < d2));
    314             break;
    315         case PSOP_LE:
    316             d2 = Pop();
    317             d1 = Pop();
    318             Push((int)(d1 <= d2));
    319             break;
    320         case PSOP_AND:
    321             i1 = (int)Pop();
    322             i2 = (int)Pop();
    323             Push(i1 & i2);
    324             break;
    325         case PSOP_OR:
    326             i1 = (int)Pop();
    327             i2 = (int)Pop();
    328             Push(i1 | i2);
    329             break;
    330         case PSOP_XOR:
    331             i1 = (int)Pop();
    332             i2 = (int)Pop();
    333             Push(i1 ^ i2);
    334             break;
    335         case PSOP_NOT:
    336             i1 = (int)Pop();
    337             Push((int)!i1);
    338             break;
    339         case PSOP_BITSHIFT: {
    340                 int shift = (int)Pop();
    341                 int i = (int)Pop();
    342                 if (shift > 0) {
    343                     Push(i << shift);
    344                 } else {
    345                     Push(i >> -shift);
    346                 }
    347                 break;
    348             }
    349         case PSOP_TRUE:
    350             Push(1);
    351             break;
    352         case PSOP_FALSE:
    353             Push(0);
    354             break;
    355         case PSOP_POP:
    356             Pop();
    357             break;
    358         case PSOP_EXCH:
    359             d2 = Pop();
    360             d1 = Pop();
    361             Push(d2);
    362             Push(d1);
    363             break;
    364         case PSOP_DUP:
    365             d1 = Pop();
    366             Push(d1);
    367             Push(d1);
    368             break;
    369         case PSOP_COPY: {
    370                 int n = (int)Pop();
    371                 if (n < 0 || n > PSENGINE_STACKSIZE || m_StackCount + n > PSENGINE_STACKSIZE || n > m_StackCount) {
    372                     break;
    373                 }
    374                 for (int i = 0; i < n; i ++) {
    375                     m_Stack[m_StackCount + i] = m_Stack[m_StackCount + i - n];
    376                 }
    377                 m_StackCount += n;
    378                 break;
    379             }
    380         case PSOP_INDEX: {
    381                 int n = (int)Pop();
    382                 if (n < 0 || n >= m_StackCount) {
    383                     break;
    384                 }
    385                 Push(m_Stack[m_StackCount - n - 1]);
    386                 break;
    387             }
    388         case PSOP_ROLL: {
    389                 int j = (int)Pop();
    390                 int n = (int)Pop();
    391                 if (m_StackCount == 0) {
    392                     break;
    393                 }
    394                 if (n < 0 || n > m_StackCount) {
    395                     break;
    396                 }
    397                 if (j < 0)
    398                     for (int i = 0; i < -j; i ++) {
    399                         FX_FLOAT first = m_Stack[m_StackCount - n];
    400                         for (int ii = 0; ii < n - 1; ii ++) {
    401                             m_Stack[m_StackCount - n + ii] = m_Stack[m_StackCount - n + ii + 1];
    402                         }
    403                         m_Stack[m_StackCount - 1] = first;
    404                     }
    405                 else
    406                     for (int i = 0; i < j; i ++) {
    407                         FX_FLOAT last = m_Stack[m_StackCount - 1];
    408                         int ii;
    409                         for (ii = 0; ii < n - 1; ii ++) {
    410                             m_Stack[m_StackCount - ii - 1] = m_Stack[m_StackCount - ii - 2];
    411                         }
    412                         m_Stack[m_StackCount - ii - 1] = last;
    413                     }
    414                 break;
    415             }
    416         default:
    417             break;
    418     }
    419     return TRUE;
    420 }
    421 static FX_FLOAT PDF_Interpolate(FX_FLOAT x, FX_FLOAT xmin, FX_FLOAT xmax, FX_FLOAT ymin, FX_FLOAT ymax)
    422 {
    423     return ((x - xmin) * (ymax - ymin) / (xmax - xmin)) + ymin;
    424 }
    425 static FX_DWORD _GetBits32(FX_LPCBYTE pData, int bitpos, int nbits)
    426 {
    427     int result = 0;
    428     for (int i = 0; i < nbits; i ++)
    429         if (pData[(bitpos + i) / 8] & (1 << (7 - (bitpos + i) % 8))) {
    430             result |= 1 << (nbits - i - 1);
    431         }
    432     return result;
    433 }
    434 typedef struct {
    435     FX_FLOAT	encode_max, encode_min;
    436     int			sizes;
    437 } SampleEncodeInfo;
    438 typedef struct {
    439     FX_FLOAT	decode_max, decode_min;
    440 } SampleDecodeInfo;
    441 class CPDF_SampledFunc : public CPDF_Function
    442 {
    443 public:
    444     CPDF_SampledFunc();
    445     virtual ~CPDF_SampledFunc();
    446     virtual FX_BOOL		v_Init(CPDF_Object* pObj);
    447     virtual FX_BOOL		v_Call(FX_FLOAT* inputs, FX_FLOAT* results) const;
    448     SampleEncodeInfo*	m_pEncodeInfo;
    449     SampleDecodeInfo*	m_pDecodeInfo;
    450     FX_DWORD	m_nBitsPerSample, m_SampleMax;
    451     CPDF_StreamAcc*	m_pSampleStream;
    452 };
    453 CPDF_SampledFunc::CPDF_SampledFunc()
    454 {
    455     m_pSampleStream = NULL;
    456     m_pEncodeInfo = NULL;
    457     m_pDecodeInfo = NULL;
    458 }
    459 CPDF_SampledFunc::~CPDF_SampledFunc()
    460 {
    461     if (m_pSampleStream) {
    462         delete m_pSampleStream;
    463     }
    464     if (m_pEncodeInfo) {
    465         FX_Free(m_pEncodeInfo);
    466     }
    467     if (m_pDecodeInfo) {
    468         FX_Free(m_pDecodeInfo);
    469     }
    470 }
    471 FX_BOOL CPDF_SampledFunc::v_Init(CPDF_Object* pObj)
    472 {
    473     if (pObj->GetType() != PDFOBJ_STREAM) {
    474         return FALSE;
    475     }
    476     CPDF_Stream* pStream = (CPDF_Stream*)pObj;
    477     CPDF_Dictionary* pDict = pStream->GetDict();
    478     CPDF_Array* pSize = pDict->GetArray(FX_BSTRC("Size"));
    479     CPDF_Array* pEncode = pDict->GetArray(FX_BSTRC("Encode"));
    480     CPDF_Array* pDecode = pDict->GetArray(FX_BSTRC("Decode"));
    481     m_nBitsPerSample = pDict->GetInteger(FX_BSTRC("BitsPerSample"));
    482     m_SampleMax = 0xffffffff >> (32 - m_nBitsPerSample);
    483     m_pSampleStream = FX_NEW CPDF_StreamAcc;
    484     m_pSampleStream->LoadAllData(pStream, FALSE);
    485     m_pEncodeInfo = FX_Alloc(SampleEncodeInfo, m_nInputs);
    486     int i;
    487     FX_DWORD nTotalSamples = 1;
    488     for (i = 0; i < m_nInputs; i ++) {
    489         m_pEncodeInfo[i].sizes = pSize->GetInteger(i);
    490         if (!pSize && i == 0) {
    491             m_pEncodeInfo[i].sizes = pDict->GetInteger(FX_BSTRC("Size"));
    492         }
    493         if (nTotalSamples > 0 && (FX_UINT32)(m_pEncodeInfo[i].sizes) > UINT_MAX / nTotalSamples) {
    494             return FALSE;
    495         }
    496         nTotalSamples *= m_pEncodeInfo[i].sizes;
    497         if (pEncode) {
    498             m_pEncodeInfo[i].encode_min = pEncode->GetFloat(i * 2);
    499             m_pEncodeInfo[i].encode_max = pEncode->GetFloat(i * 2 + 1);
    500         } else {
    501             m_pEncodeInfo[i].encode_min = 0;
    502             if (m_pEncodeInfo[i].sizes == 1) {
    503                 m_pEncodeInfo[i].encode_max = 1;
    504             } else {
    505                 m_pEncodeInfo[i].encode_max = (FX_FLOAT)m_pEncodeInfo[i].sizes - 1;
    506             }
    507         }
    508     }
    509     if (nTotalSamples > 0 && m_nBitsPerSample > UINT_MAX / nTotalSamples) {
    510         return FALSE;
    511     }
    512     nTotalSamples *= m_nBitsPerSample;
    513     if (nTotalSamples > 0 && ((FX_UINT32)m_nOutputs) > UINT_MAX / nTotalSamples) {
    514         return FALSE;
    515     }
    516     nTotalSamples *= m_nOutputs;
    517     if (nTotalSamples == 0 || m_pSampleStream->GetSize() * 8 < nTotalSamples) {
    518         return FALSE;
    519     }
    520     m_pDecodeInfo = FX_Alloc(SampleDecodeInfo, m_nOutputs);
    521     for (i = 0; i < m_nOutputs; i ++) {
    522         if (pDecode) {
    523             m_pDecodeInfo[i].decode_min = pDecode->GetFloat(2 * i);
    524             m_pDecodeInfo[i].decode_max = pDecode->GetFloat(2 * i + 1);
    525         } else {
    526             m_pDecodeInfo[i].decode_min = m_pRanges[i * 2];
    527             m_pDecodeInfo[i].decode_max = m_pRanges[i * 2 + 1];
    528         }
    529     }
    530     return TRUE;
    531 }
    532 FX_BOOL CPDF_SampledFunc::v_Call(FX_FLOAT* inputs, FX_FLOAT* results) const
    533 {
    534     int pos = 0;
    535     CFX_FixedBufGrow<FX_FLOAT, 16> encoded_input_buf(m_nInputs);
    536     FX_FLOAT* encoded_input = encoded_input_buf;
    537     CFX_FixedBufGrow<int, 32> int_buf(m_nInputs * 2);
    538     int* index = int_buf;
    539     int* blocksize = index + m_nInputs;
    540     for (int i = 0; i < m_nInputs; i ++) {
    541         if (i == 0) {
    542             blocksize[i] = 1;
    543         } else {
    544             blocksize[i] = blocksize[i - 1] * m_pEncodeInfo[i - 1].sizes;
    545         }
    546         encoded_input[i] = PDF_Interpolate(inputs[i], m_pDomains[i * 2], m_pDomains[i * 2 + 1],
    547                                            m_pEncodeInfo[i].encode_min, m_pEncodeInfo[i].encode_max);
    548         index[i] = (int)encoded_input[i];
    549         if (index[i] < 0) {
    550             index[i] = 0;
    551         } else if (index[i] > m_pEncodeInfo[i].sizes - 1) {
    552             index[i] = m_pEncodeInfo[i].sizes - 1;
    553         }
    554         pos += index[i] * blocksize[i];
    555     }
    556     int bitpos = pos * m_nBitsPerSample * m_nOutputs;
    557     FX_LPCBYTE pSampleData = m_pSampleStream->GetData();
    558     if (pSampleData == NULL) {
    559         return FALSE;
    560     }
    561     for (int j = 0; j < m_nOutputs; j ++) {
    562         FX_DWORD sample = _GetBits32(pSampleData, bitpos + j * m_nBitsPerSample, m_nBitsPerSample);
    563         FX_FLOAT encoded = (FX_FLOAT)sample;
    564         for (int i = 0; i < m_nInputs; i ++) {
    565             if (index[i] == m_pEncodeInfo[i].sizes - 1) {
    566                 if (index[i] == 0) {
    567                     encoded = encoded_input[i] * (FX_FLOAT)sample;
    568                 }
    569             } else {
    570                 int bitpos1 = bitpos + m_nBitsPerSample * m_nOutputs * blocksize[i];
    571                 FX_DWORD sample1 = _GetBits32(pSampleData, bitpos1 + j * m_nBitsPerSample, m_nBitsPerSample);
    572                 encoded += (encoded_input[i] - index[i]) * ((FX_FLOAT)sample1 - (FX_FLOAT)sample);
    573             }
    574         }
    575         results[j] = PDF_Interpolate(encoded, 0, (FX_FLOAT)m_SampleMax,
    576                                      m_pDecodeInfo[j].decode_min, m_pDecodeInfo[j].decode_max);
    577     }
    578     return TRUE;
    579 }
    580 class CPDF_PSFunc : public CPDF_Function
    581 {
    582 public:
    583     virtual FX_BOOL		v_Init(CPDF_Object* pObj);
    584     virtual FX_BOOL		v_Call(FX_FLOAT* inputs, FX_FLOAT* results) const;
    585     CPDF_PSEngine m_PS;
    586 };
    587 FX_BOOL CPDF_PSFunc::v_Init(CPDF_Object* pObj)
    588 {
    589     CPDF_Stream* pStream = (CPDF_Stream*)pObj;
    590     CPDF_StreamAcc acc;
    591     acc.LoadAllData(pStream, FALSE);
    592     return m_PS.Parse((const FX_CHAR*)acc.GetData(), acc.GetSize());
    593 }
    594 FX_BOOL CPDF_PSFunc::v_Call(FX_FLOAT* inputs, FX_FLOAT* results) const
    595 {
    596     CPDF_PSEngine& PS = (CPDF_PSEngine&)m_PS;
    597     PS.Reset();
    598     int i;
    599     for (i = 0; i < m_nInputs; i ++) {
    600         PS.Push(inputs[i]);
    601     }
    602     PS.Execute();
    603     if (PS.GetStackSize() < m_nOutputs) {
    604         return FALSE;
    605     }
    606     for (i = 0; i < m_nOutputs; i ++) {
    607         results[m_nOutputs - i - 1] = PS.Pop();
    608     }
    609     return TRUE;
    610 }
    611 class CPDF_ExpIntFunc : public CPDF_Function
    612 {
    613 public:
    614     CPDF_ExpIntFunc();
    615     virtual ~CPDF_ExpIntFunc();
    616     virtual FX_BOOL		v_Init(CPDF_Object* pObj);
    617     virtual FX_BOOL		v_Call(FX_FLOAT* inputs, FX_FLOAT* results) const;
    618     FX_FLOAT	m_Exponent;
    619     FX_FLOAT*	m_pBeginValues;
    620     FX_FLOAT*	m_pEndValues;
    621     int		m_nOrigOutputs;
    622 };
    623 CPDF_ExpIntFunc::CPDF_ExpIntFunc()
    624 {
    625     m_pBeginValues = NULL;
    626     m_pEndValues = NULL;
    627 }
    628 CPDF_ExpIntFunc::~CPDF_ExpIntFunc()
    629 {
    630     if (m_pBeginValues) {
    631         FX_Free(m_pBeginValues);
    632     }
    633     if (m_pEndValues) {
    634         FX_Free(m_pEndValues);
    635     }
    636 }
    637 FX_BOOL CPDF_ExpIntFunc::v_Init(CPDF_Object* pObj)
    638 {
    639     CPDF_Dictionary* pDict = pObj->GetDict();
    640     if (pDict == NULL) {
    641         return FALSE;
    642     }
    643     CPDF_Array* pArray0 = pDict->GetArray(FX_BSTRC("C0"));
    644     if (m_nOutputs == 0) {
    645         m_nOutputs = 1;
    646         if (pArray0) {
    647             m_nOutputs = pArray0->GetCount();
    648         }
    649     }
    650     CPDF_Array* pArray1 = pDict->GetArray(FX_BSTRC("C1"));
    651     m_pBeginValues = FX_Alloc(FX_FLOAT, m_nOutputs * 2);
    652     m_pEndValues = FX_Alloc(FX_FLOAT, m_nOutputs * 2);
    653     for (int i = 0; i < m_nOutputs; i ++) {
    654         m_pBeginValues[i] = pArray0 ? pArray0->GetFloat(i) : 0.0f;
    655         m_pEndValues[i] = pArray1 ? pArray1->GetFloat(i) : 1.0f;
    656     }
    657     m_Exponent = pDict->GetFloat(FX_BSTRC("N"));
    658     m_nOrigOutputs = m_nOutputs;
    659     if (m_nOutputs && m_nInputs > INT_MAX / m_nOutputs) {
    660         return FALSE;
    661     }
    662     m_nOutputs *= m_nInputs;
    663     return TRUE;
    664 }
    665 FX_BOOL CPDF_ExpIntFunc::v_Call(FX_FLOAT* inputs, FX_FLOAT* results) const
    666 {
    667     for (int i = 0; i < m_nInputs; i ++)
    668         for (int j = 0; j < m_nOrigOutputs; j ++) {
    669             results[i * m_nOrigOutputs + j] = m_pBeginValues[j] + (FX_FLOAT)FXSYS_pow(inputs[i], m_Exponent) *
    670                                               (m_pEndValues[j] - m_pBeginValues[j]);
    671         }
    672     return TRUE;
    673 }
    674 class CPDF_StitchFunc : public CPDF_Function
    675 {
    676 public:
    677     CPDF_StitchFunc();
    678     virtual ~CPDF_StitchFunc();
    679     virtual FX_BOOL		v_Init(CPDF_Object* pObj);
    680     virtual FX_BOOL		v_Call(FX_FLOAT* inputs, FX_FLOAT* results) const;
    681     int			m_nSubs;
    682     CPDF_Function** m_pSubFunctions;
    683     FX_FLOAT*	m_pBounds;
    684     FX_FLOAT*	m_pEncode;
    685 };
    686 CPDF_StitchFunc::CPDF_StitchFunc()
    687 {
    688     m_nSubs = 0;
    689     m_pSubFunctions = NULL;
    690     m_pBounds = NULL;
    691     m_pEncode = NULL;
    692 }
    693 CPDF_StitchFunc::~CPDF_StitchFunc()
    694 {
    695     for (int i = 0; i < m_nSubs; i ++)
    696         if (m_pSubFunctions[i]) {
    697             delete m_pSubFunctions[i];
    698         }
    699     if (m_pSubFunctions) {
    700         FX_Free(m_pSubFunctions);
    701     }
    702     if (m_pBounds) {
    703         FX_Free(m_pBounds);
    704     }
    705     if (m_pEncode) {
    706         FX_Free(m_pEncode);
    707     }
    708 }
    709 FX_BOOL CPDF_StitchFunc::v_Init(CPDF_Object* pObj)
    710 {
    711     CPDF_Dictionary* pDict = pObj->GetDict();
    712     if (pDict == NULL) {
    713         return FALSE;
    714     }
    715     CPDF_Array* pArray = pDict->GetArray(FX_BSTRC("Functions"));
    716     if (pArray == NULL) {
    717         return FALSE;
    718     }
    719     m_nSubs = pArray->GetCount();
    720     if (m_nSubs == 0) {
    721         return FALSE;
    722     }
    723     m_pSubFunctions = FX_Alloc(CPDF_Function*, m_nSubs);
    724     FXSYS_memset32(m_pSubFunctions, 0, sizeof(CPDF_Function*)*m_nSubs);
    725     m_nOutputs = 0;
    726     int i;
    727     for (i = 0; i < m_nSubs; i ++) {
    728         CPDF_Object* pSub = pArray->GetElementValue(i);
    729         if (pSub == pObj) {
    730             return FALSE;
    731         }
    732         m_pSubFunctions[i] = CPDF_Function::Load(pSub);
    733         if (m_pSubFunctions[i] == NULL) {
    734             return FALSE;
    735         }
    736         if (m_pSubFunctions[i]->CountOutputs() > m_nOutputs) {
    737             m_nOutputs = m_pSubFunctions[i]->CountOutputs();
    738         }
    739     }
    740     m_pBounds = FX_Alloc(FX_FLOAT, m_nSubs + 1);
    741     m_pBounds[0] = m_pDomains[0];
    742     pArray = pDict->GetArray(FX_BSTRC("Bounds"));
    743     if (pArray == NULL) {
    744         return FALSE;
    745     }
    746     for (i = 0; i < m_nSubs - 1; i ++) {
    747         m_pBounds[i + 1] = pArray->GetFloat(i);
    748     }
    749     m_pBounds[m_nSubs] = m_pDomains[1];
    750     m_pEncode = FX_Alloc(FX_FLOAT, m_nSubs * 2);
    751     pArray = pDict->GetArray(FX_BSTRC("Encode"));
    752     if (pArray == NULL) {
    753         return FALSE;
    754     }
    755     for (i = 0; i < m_nSubs * 2; i ++) {
    756         m_pEncode[i] = pArray->GetFloat(i);
    757     }
    758     return TRUE;
    759 }
    760 FX_BOOL CPDF_StitchFunc::v_Call(FX_FLOAT* inputs, FX_FLOAT* outputs) const
    761 {
    762     FX_FLOAT input = inputs[0];
    763     int i;
    764     for (i = 0; i < m_nSubs - 1; i ++)
    765         if (input < m_pBounds[i + 1]) {
    766             break;
    767         }
    768     if (m_pSubFunctions[i] == NULL) {
    769         return FALSE;
    770     }
    771     input = PDF_Interpolate(input, m_pBounds[i], m_pBounds[i + 1], m_pEncode[i * 2], m_pEncode[i * 2 + 1]);
    772     int nresults;
    773     m_pSubFunctions[i]->Call(&input, m_nInputs, outputs, nresults);
    774     return TRUE;
    775 }
    776 CPDF_Function* CPDF_Function::Load(CPDF_Object* pFuncObj)
    777 {
    778     if (pFuncObj == NULL) {
    779         return NULL;
    780     }
    781     CPDF_Function* pFunc = NULL;
    782     int type;
    783     if (pFuncObj->GetType() == PDFOBJ_STREAM) {
    784         type = ((CPDF_Stream*)pFuncObj)->GetDict()->GetInteger(FX_BSTRC("FunctionType"));
    785     } else if (pFuncObj->GetType() == PDFOBJ_DICTIONARY) {
    786         type = ((CPDF_Dictionary*)pFuncObj)->GetInteger(FX_BSTRC("FunctionType"));
    787     } else {
    788         return NULL;
    789     }
    790     if (type == 0) {
    791         pFunc = FX_NEW CPDF_SampledFunc;
    792     } else if (type == 2) {
    793         pFunc = FX_NEW CPDF_ExpIntFunc;
    794     } else if (type == 3) {
    795         pFunc = FX_NEW CPDF_StitchFunc;
    796     } else if (type == 4) {
    797         pFunc = FX_NEW CPDF_PSFunc;
    798     } else {
    799         return NULL;
    800     }
    801     if (!pFunc->Init(pFuncObj)) {
    802         delete pFunc;
    803         return NULL;
    804     }
    805     return pFunc;
    806 }
    807 CPDF_Function::CPDF_Function()
    808 {
    809     m_pDomains = NULL;
    810     m_pRanges = NULL;
    811 }
    812 CPDF_Function::~CPDF_Function()
    813 {
    814     if (m_pDomains) {
    815         FX_Free(m_pDomains);
    816         m_pDomains = NULL;
    817     }
    818     if (m_pRanges) {
    819         FX_Free(m_pRanges);
    820         m_pRanges = NULL;
    821     }
    822 }
    823 FX_BOOL CPDF_Function::Init(CPDF_Object* pObj)
    824 {
    825     CPDF_Dictionary* pDict;
    826     if (pObj->GetType() == PDFOBJ_STREAM) {
    827         pDict = ((CPDF_Stream*)pObj)->GetDict();
    828     } else {
    829         pDict = (CPDF_Dictionary*)pObj;
    830     }
    831     CPDF_Array* pDomains = pDict->GetArray(FX_BSTRC("Domain"));
    832     if (pDomains == NULL) {
    833         return FALSE;
    834     }
    835     m_nInputs = pDomains->GetCount() / 2;
    836     if (m_nInputs == 0) {
    837         return FALSE;
    838     }
    839     m_pDomains = FX_Alloc(FX_FLOAT, m_nInputs * 2);
    840     for (int i = 0; i < m_nInputs * 2; i ++) {
    841         m_pDomains[i] = pDomains->GetFloat(i);
    842     }
    843     CPDF_Array* pRanges = pDict->GetArray(FX_BSTRC("Range"));
    844     m_nOutputs = 0;
    845     if (pRanges) {
    846         m_nOutputs = pRanges->GetCount() / 2;
    847         m_pRanges = FX_Alloc(FX_FLOAT, m_nOutputs * 2);
    848         for (int i = 0; i < m_nOutputs * 2; i ++) {
    849             m_pRanges[i] = pRanges->GetFloat(i);
    850         }
    851     }
    852     FX_DWORD old_outputs = m_nOutputs;
    853     FX_BOOL ret = v_Init(pObj);
    854     if (m_pRanges && m_nOutputs > (int)old_outputs) {
    855         m_pRanges = FX_Realloc(FX_FLOAT, m_pRanges, m_nOutputs * 2);
    856         if (m_pRanges) {
    857             FXSYS_memset32(m_pRanges + (old_outputs * 2), 0, sizeof(FX_FLOAT) * (m_nOutputs - old_outputs) * 2);
    858         }
    859     }
    860     return ret;
    861 }
    862 FX_BOOL CPDF_Function::Call(FX_FLOAT* inputs, int ninputs, FX_FLOAT* results, int& nresults) const
    863 {
    864     if (m_nInputs != ninputs) {
    865         return FALSE;
    866     }
    867     nresults = m_nOutputs;
    868     for (int i = 0; i < m_nInputs; i ++) {
    869         if (inputs[i] < m_pDomains[i * 2]) {
    870             inputs[i] = m_pDomains[i * 2];
    871         } else if (inputs[i] > m_pDomains[i * 2 + 1]) {
    872             inputs[i] = m_pDomains[i * 2] + 1;
    873         }
    874     }
    875     v_Call(inputs, results);
    876     if (m_pRanges) {
    877         for (int i = 0; i < m_nOutputs; i ++) {
    878             if (results[i] < m_pRanges[i * 2]) {
    879                 results[i] = m_pRanges[i * 2];
    880             } else if (results[i] > m_pRanges[i * 2 + 1]) {
    881                 results[i] = m_pRanges[i * 2 + 1];
    882             }
    883         }
    884     }
    885     return TRUE;
    886 }
    887