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