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