87ff0a3b634a209074cd22d70f367120446f0c57
[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 class CPDF_SampledFunc : public CPDF_Function {
467  public:
468   CPDF_SampledFunc();
469   virtual ~CPDF_SampledFunc();
470   virtual FX_BOOL v_Init(CPDF_Object* pObj);
471   virtual FX_BOOL v_Call(FX_FLOAT* inputs, FX_FLOAT* results) const;
472   SampleEncodeInfo* m_pEncodeInfo;
473   SampleDecodeInfo* m_pDecodeInfo;
474   FX_DWORD m_nBitsPerSample;
475   FX_DWORD m_SampleMax;
476   CPDF_StreamAcc* m_pSampleStream;
477 };
478 CPDF_SampledFunc::CPDF_SampledFunc() {
479   m_pSampleStream = NULL;
480   m_pEncodeInfo = NULL;
481   m_pDecodeInfo = NULL;
482 }
483 CPDF_SampledFunc::~CPDF_SampledFunc() {
484   delete m_pSampleStream;
485   if (m_pEncodeInfo) {
486     FX_Free(m_pEncodeInfo);
487   }
488   if (m_pDecodeInfo) {
489     FX_Free(m_pDecodeInfo);
490   }
491 }
492 FX_BOOL CPDF_SampledFunc::v_Init(CPDF_Object* pObj) {
493   if (pObj->GetType() != PDFOBJ_STREAM) {
494     return FALSE;
495   }
496   CPDF_Stream* pStream = (CPDF_Stream*)pObj;
497   CPDF_Dictionary* pDict = pStream->GetDict();
498   CPDF_Array* pSize = pDict->GetArray(FX_BSTRC("Size"));
499   CPDF_Array* pEncode = pDict->GetArray(FX_BSTRC("Encode"));
500   CPDF_Array* pDecode = pDict->GetArray(FX_BSTRC("Decode"));
501   m_nBitsPerSample = pDict->GetInteger(FX_BSTRC("BitsPerSample"));
502   if (m_nBitsPerSample > 32) {
503     return FALSE;
504   }
505   m_SampleMax = 0xffffffff >> (32 - m_nBitsPerSample);
506   m_pSampleStream = new CPDF_StreamAcc;
507   m_pSampleStream->LoadAllData(pStream, FALSE);
508   m_pEncodeInfo = FX_Alloc(SampleEncodeInfo, m_nInputs);
509   FX_SAFE_DWORD nTotalSampleBits = 1;
510   for (int i = 0; i < m_nInputs; i++) {
511     m_pEncodeInfo[i].sizes = pSize ? pSize->GetInteger(i) : 0;
512     if (!pSize && i == 0) {
513       m_pEncodeInfo[i].sizes = pDict->GetInteger(FX_BSTRC("Size"));
514     }
515     nTotalSampleBits *= m_pEncodeInfo[i].sizes;
516     if (pEncode) {
517       m_pEncodeInfo[i].encode_min = pEncode->GetFloat(i * 2);
518       m_pEncodeInfo[i].encode_max = pEncode->GetFloat(i * 2 + 1);
519     } else {
520       m_pEncodeInfo[i].encode_min = 0;
521       if (m_pEncodeInfo[i].sizes == 1) {
522         m_pEncodeInfo[i].encode_max = 1;
523       } else {
524         m_pEncodeInfo[i].encode_max = (FX_FLOAT)m_pEncodeInfo[i].sizes - 1;
525       }
526     }
527   }
528   nTotalSampleBits *= m_nBitsPerSample;
529   nTotalSampleBits *= m_nOutputs;
530   FX_SAFE_DWORD nTotalSampleBytes = nTotalSampleBits;
531   nTotalSampleBytes += 7;
532   nTotalSampleBytes /= 8;
533   if (!nTotalSampleBytes.IsValid() || nTotalSampleBytes.ValueOrDie() == 0 ||
534       nTotalSampleBytes.ValueOrDie() > m_pSampleStream->GetSize()) {
535     return FALSE;
536   }
537   m_pDecodeInfo = FX_Alloc(SampleDecodeInfo, m_nOutputs);
538   for (int i = 0; i < m_nOutputs; i++) {
539     if (pDecode) {
540       m_pDecodeInfo[i].decode_min = pDecode->GetFloat(2 * i);
541       m_pDecodeInfo[i].decode_max = pDecode->GetFloat(2 * i + 1);
542     } else {
543       m_pDecodeInfo[i].decode_min = m_pRanges[i * 2];
544       m_pDecodeInfo[i].decode_max = m_pRanges[i * 2 + 1];
545     }
546   }
547   return TRUE;
548 }
549 FX_BOOL CPDF_SampledFunc::v_Call(FX_FLOAT* inputs, FX_FLOAT* results) const {
550   int pos = 0;
551   CFX_FixedBufGrow<FX_FLOAT, 16> encoded_input_buf(m_nInputs);
552   FX_FLOAT* encoded_input = encoded_input_buf;
553   CFX_FixedBufGrow<int, 32> int_buf(m_nInputs * 2);
554   int* index = int_buf;
555   int* blocksize = index + m_nInputs;
556   for (int i = 0; i < m_nInputs; i++) {
557     if (i == 0) {
558       blocksize[i] = 1;
559     } else {
560       blocksize[i] = blocksize[i - 1] * m_pEncodeInfo[i - 1].sizes;
561     }
562     encoded_input[i] = PDF_Interpolate(
563         inputs[i], m_pDomains[i * 2], m_pDomains[i * 2 + 1],
564         m_pEncodeInfo[i].encode_min, m_pEncodeInfo[i].encode_max);
565     index[i] = (int)encoded_input[i];
566     if (index[i] < 0) {
567       index[i] = 0;
568     } else if (index[i] > m_pEncodeInfo[i].sizes - 1) {
569       index[i] = m_pEncodeInfo[i].sizes - 1;
570     }
571     pos += index[i] * blocksize[i];
572   }
573   FX_SAFE_INT32 bits_to_output = m_nOutputs;
574   bits_to_output *= m_nBitsPerSample;
575   if (!bits_to_output.IsValid()) {
576     return FALSE;
577   }
578   FX_SAFE_INT32 bitpos = pos;
579   bitpos *= bits_to_output.ValueOrDie();
580   if (!bitpos.IsValid()) {
581     return FALSE;
582   }
583   FX_SAFE_INT32 range_check = bitpos;
584   range_check += bits_to_output.ValueOrDie();
585   if (!range_check.IsValid()) {
586     return FALSE;
587   }
588   const uint8_t* pSampleData = m_pSampleStream->GetData();
589   if (!pSampleData) {
590     return FALSE;
591   }
592   for (int j = 0; j < m_nOutputs; j++) {
593     FX_DWORD sample =
594         _GetBits32(pSampleData, bitpos.ValueOrDie() + j * m_nBitsPerSample,
595                    m_nBitsPerSample);
596     FX_FLOAT encoded = (FX_FLOAT)sample;
597     for (int i = 0; i < m_nInputs; i++) {
598       if (index[i] == m_pEncodeInfo[i].sizes - 1) {
599         if (index[i] == 0) {
600           encoded = encoded_input[i] * (FX_FLOAT)sample;
601         }
602       } else {
603         FX_SAFE_INT32 bitpos2 = blocksize[i];
604         bitpos2 += pos;
605         bitpos2 *= m_nOutputs;
606         bitpos2 += j;
607         bitpos2 *= m_nBitsPerSample;
608         if (!bitpos2.IsValid()) {
609           return FALSE;
610         }
611         FX_DWORD sample1 =
612             _GetBits32(pSampleData, bitpos2.ValueOrDie(), m_nBitsPerSample);
613         encoded += (encoded_input[i] - index[i]) *
614                    ((FX_FLOAT)sample1 - (FX_FLOAT)sample);
615       }
616     }
617     results[j] = PDF_Interpolate(encoded, 0, (FX_FLOAT)m_SampleMax,
618                                  m_pDecodeInfo[j].decode_min,
619                                  m_pDecodeInfo[j].decode_max);
620   }
621   return TRUE;
622 }
623 class CPDF_PSFunc : public CPDF_Function {
624  public:
625   virtual FX_BOOL v_Init(CPDF_Object* pObj);
626   virtual FX_BOOL v_Call(FX_FLOAT* inputs, FX_FLOAT* results) const;
627   CPDF_PSEngine m_PS;
628 };
629 FX_BOOL CPDF_PSFunc::v_Init(CPDF_Object* pObj) {
630   CPDF_Stream* pStream = (CPDF_Stream*)pObj;
631   CPDF_StreamAcc acc;
632   acc.LoadAllData(pStream, FALSE);
633   return m_PS.Parse((const FX_CHAR*)acc.GetData(), acc.GetSize());
634 }
635 FX_BOOL CPDF_PSFunc::v_Call(FX_FLOAT* inputs, FX_FLOAT* results) const {
636   CPDF_PSEngine& PS = (CPDF_PSEngine&)m_PS;
637   PS.Reset();
638   int i;
639   for (i = 0; i < m_nInputs; i++) {
640     PS.Push(inputs[i]);
641   }
642   PS.Execute();
643   if (PS.GetStackSize() < m_nOutputs) {
644     return FALSE;
645   }
646   for (i = 0; i < m_nOutputs; i++) {
647     results[m_nOutputs - i - 1] = PS.Pop();
648   }
649   return TRUE;
650 }
651 class CPDF_ExpIntFunc : public CPDF_Function {
652  public:
653   CPDF_ExpIntFunc();
654   virtual ~CPDF_ExpIntFunc();
655   virtual FX_BOOL v_Init(CPDF_Object* pObj);
656   virtual FX_BOOL v_Call(FX_FLOAT* inputs, FX_FLOAT* results) const;
657   FX_FLOAT m_Exponent;
658   FX_FLOAT* m_pBeginValues;
659   FX_FLOAT* m_pEndValues;
660   int m_nOrigOutputs;
661 };
662 CPDF_ExpIntFunc::CPDF_ExpIntFunc() {
663   m_pBeginValues = NULL;
664   m_pEndValues = NULL;
665 }
666 CPDF_ExpIntFunc::~CPDF_ExpIntFunc() {
667   if (m_pBeginValues) {
668     FX_Free(m_pBeginValues);
669   }
670   if (m_pEndValues) {
671     FX_Free(m_pEndValues);
672   }
673 }
674 FX_BOOL CPDF_ExpIntFunc::v_Init(CPDF_Object* pObj) {
675   CPDF_Dictionary* pDict = pObj->GetDict();
676   if (pDict == NULL) {
677     return FALSE;
678   }
679   CPDF_Array* pArray0 = pDict->GetArray(FX_BSTRC("C0"));
680   if (m_nOutputs == 0) {
681     m_nOutputs = 1;
682     if (pArray0) {
683       m_nOutputs = pArray0->GetCount();
684     }
685   }
686   CPDF_Array* pArray1 = pDict->GetArray(FX_BSTRC("C1"));
687   m_pBeginValues = FX_Alloc2D(FX_FLOAT, m_nOutputs, 2);
688   m_pEndValues = FX_Alloc2D(FX_FLOAT, m_nOutputs, 2);
689   for (int i = 0; i < m_nOutputs; i++) {
690     m_pBeginValues[i] = pArray0 ? pArray0->GetFloat(i) : 0.0f;
691     m_pEndValues[i] = pArray1 ? pArray1->GetFloat(i) : 1.0f;
692   }
693   m_Exponent = pDict->GetFloat(FX_BSTRC("N"));
694   m_nOrigOutputs = m_nOutputs;
695   if (m_nOutputs && m_nInputs > INT_MAX / m_nOutputs) {
696     return FALSE;
697   }
698   m_nOutputs *= m_nInputs;
699   return TRUE;
700 }
701 FX_BOOL CPDF_ExpIntFunc::v_Call(FX_FLOAT* inputs, FX_FLOAT* results) const {
702   for (int i = 0; i < m_nInputs; i++)
703     for (int j = 0; j < m_nOrigOutputs; j++) {
704       results[i * m_nOrigOutputs + j] =
705           m_pBeginValues[j] +
706           (FX_FLOAT)FXSYS_pow(inputs[i], m_Exponent) *
707               (m_pEndValues[j] - m_pBeginValues[j]);
708     }
709   return TRUE;
710 }
711 class CPDF_StitchFunc : public CPDF_Function {
712  public:
713   CPDF_StitchFunc();
714   virtual ~CPDF_StitchFunc();
715   virtual FX_BOOL v_Init(CPDF_Object* pObj);
716   virtual FX_BOOL v_Call(FX_FLOAT* inputs, FX_FLOAT* results) const;
717   int m_nSubs;
718   CPDF_Function** m_pSubFunctions;
719   FX_FLOAT* m_pBounds;
720   FX_FLOAT* m_pEncode;
721 };
722 CPDF_StitchFunc::CPDF_StitchFunc() {
723   m_nSubs = 0;
724   m_pSubFunctions = NULL;
725   m_pBounds = NULL;
726   m_pEncode = NULL;
727 }
728 CPDF_StitchFunc::~CPDF_StitchFunc() {
729   for (int i = 0; i < m_nSubs; i++)
730     delete m_pSubFunctions[i];
731   if (m_pSubFunctions) {
732     FX_Free(m_pSubFunctions);
733   }
734   if (m_pBounds) {
735     FX_Free(m_pBounds);
736   }
737   if (m_pEncode) {
738     FX_Free(m_pEncode);
739   }
740 }
741 FX_BOOL CPDF_StitchFunc::v_Init(CPDF_Object* pObj) {
742   CPDF_Dictionary* pDict = pObj->GetDict();
743   if (pDict == NULL) {
744     return FALSE;
745   }
746   CPDF_Array* pArray = pDict->GetArray(FX_BSTRC("Functions"));
747   if (pArray == NULL) {
748     return FALSE;
749   }
750   m_nSubs = pArray->GetCount();
751   if (m_nSubs == 0) {
752     return FALSE;
753   }
754   m_pSubFunctions = FX_Alloc(CPDF_Function*, m_nSubs);
755   m_nOutputs = 0;
756   int i;
757   for (i = 0; i < m_nSubs; i++) {
758     CPDF_Object* pSub = pArray->GetElementValue(i);
759     if (pSub == pObj) {
760       return FALSE;
761     }
762     m_pSubFunctions[i] = CPDF_Function::Load(pSub);
763     if (m_pSubFunctions[i] == NULL) {
764       return FALSE;
765     }
766     if (m_pSubFunctions[i]->CountOutputs() > m_nOutputs) {
767       m_nOutputs = m_pSubFunctions[i]->CountOutputs();
768     }
769   }
770   m_pBounds = FX_Alloc(FX_FLOAT, m_nSubs + 1);
771   m_pBounds[0] = m_pDomains[0];
772   pArray = pDict->GetArray(FX_BSTRC("Bounds"));
773   if (pArray == NULL) {
774     return FALSE;
775   }
776   for (i = 0; i < m_nSubs - 1; i++) {
777     m_pBounds[i + 1] = pArray->GetFloat(i);
778   }
779   m_pBounds[m_nSubs] = m_pDomains[1];
780   m_pEncode = FX_Alloc2D(FX_FLOAT, m_nSubs, 2);
781   pArray = pDict->GetArray(FX_BSTRC("Encode"));
782   if (pArray == NULL) {
783     return FALSE;
784   }
785   for (i = 0; i < m_nSubs * 2; i++) {
786     m_pEncode[i] = pArray->GetFloat(i);
787   }
788   return TRUE;
789 }
790 FX_BOOL CPDF_StitchFunc::v_Call(FX_FLOAT* inputs, FX_FLOAT* outputs) const {
791   FX_FLOAT input = inputs[0];
792   int i;
793   for (i = 0; i < m_nSubs - 1; i++)
794     if (input < m_pBounds[i + 1]) {
795       break;
796     }
797   if (m_pSubFunctions[i] == NULL) {
798     return FALSE;
799   }
800   input = PDF_Interpolate(input, m_pBounds[i], m_pBounds[i + 1],
801                           m_pEncode[i * 2], m_pEncode[i * 2 + 1]);
802   int nresults;
803   m_pSubFunctions[i]->Call(&input, m_nInputs, outputs, nresults);
804   return TRUE;
805 }
806 CPDF_Function* CPDF_Function::Load(CPDF_Object* pFuncObj) {
807   if (pFuncObj == NULL) {
808     return NULL;
809   }
810   CPDF_Function* pFunc = NULL;
811   int type;
812   if (pFuncObj->GetType() == PDFOBJ_STREAM) {
813     type = ((CPDF_Stream*)pFuncObj)
814                ->GetDict()
815                ->GetInteger(FX_BSTRC("FunctionType"));
816   } else if (pFuncObj->GetType() == PDFOBJ_DICTIONARY) {
817     type = ((CPDF_Dictionary*)pFuncObj)->GetInteger(FX_BSTRC("FunctionType"));
818   } else {
819     return NULL;
820   }
821   if (type == 0) {
822     pFunc = new CPDF_SampledFunc;
823   } else if (type == 2) {
824     pFunc = new CPDF_ExpIntFunc;
825   } else if (type == 3) {
826     pFunc = new CPDF_StitchFunc;
827   } else if (type == 4) {
828     pFunc = new CPDF_PSFunc;
829   } else {
830     return NULL;
831   }
832   if (!pFunc->Init(pFuncObj)) {
833     delete pFunc;
834     return NULL;
835   }
836   return pFunc;
837 }
838 CPDF_Function::CPDF_Function() {
839   m_pDomains = NULL;
840   m_pRanges = NULL;
841 }
842 CPDF_Function::~CPDF_Function() {
843   if (m_pDomains) {
844     FX_Free(m_pDomains);
845     m_pDomains = NULL;
846   }
847   if (m_pRanges) {
848     FX_Free(m_pRanges);
849     m_pRanges = NULL;
850   }
851 }
852 FX_BOOL CPDF_Function::Init(CPDF_Object* pObj) {
853   CPDF_Dictionary* pDict;
854   if (pObj->GetType() == PDFOBJ_STREAM) {
855     pDict = ((CPDF_Stream*)pObj)->GetDict();
856   } else {
857     pDict = (CPDF_Dictionary*)pObj;
858   }
859   CPDF_Array* pDomains = pDict->GetArray(FX_BSTRC("Domain"));
860   if (pDomains == NULL) {
861     return FALSE;
862   }
863   m_nInputs = pDomains->GetCount() / 2;
864   if (m_nInputs == 0) {
865     return FALSE;
866   }
867   m_pDomains = FX_Alloc2D(FX_FLOAT, m_nInputs, 2);
868   for (int i = 0; i < m_nInputs * 2; i++) {
869     m_pDomains[i] = pDomains->GetFloat(i);
870   }
871   CPDF_Array* pRanges = pDict->GetArray(FX_BSTRC("Range"));
872   m_nOutputs = 0;
873   if (pRanges) {
874     m_nOutputs = pRanges->GetCount() / 2;
875     m_pRanges = FX_Alloc2D(FX_FLOAT, m_nOutputs, 2);
876     for (int i = 0; i < m_nOutputs * 2; i++) {
877       m_pRanges[i] = pRanges->GetFloat(i);
878     }
879   }
880   FX_DWORD old_outputs = m_nOutputs;
881   if (!v_Init(pObj)) {
882     return FALSE;
883   }
884   if (m_pRanges && m_nOutputs > (int)old_outputs) {
885     m_pRanges = FX_Realloc(FX_FLOAT, m_pRanges, m_nOutputs * 2);
886     if (m_pRanges) {
887       FXSYS_memset(m_pRanges + (old_outputs * 2), 0,
888                    sizeof(FX_FLOAT) * (m_nOutputs - old_outputs) * 2);
889     }
890   }
891   return TRUE;
892 }
893 FX_BOOL CPDF_Function::Call(FX_FLOAT* inputs,
894                             int ninputs,
895                             FX_FLOAT* results,
896                             int& nresults) const {
897   if (m_nInputs != ninputs) {
898     return FALSE;
899   }
900   nresults = m_nOutputs;
901   for (int i = 0; i < m_nInputs; i++) {
902     if (inputs[i] < m_pDomains[i * 2]) {
903       inputs[i] = m_pDomains[i * 2];
904     } else if (inputs[i] > m_pDomains[i * 2 + 1]) {
905       inputs[i] = m_pDomains[i * 2] + 1;
906     }
907   }
908   v_Call(inputs, results);
909   if (m_pRanges) {
910     for (int i = 0; i < m_nOutputs; i++) {
911       if (results[i] < m_pRanges[i * 2]) {
912         results[i] = m_pRanges[i * 2];
913       } else if (results[i] > m_pRanges[i * 2 + 1]) {
914         results[i] = m_pRanges[i * 2 + 1];
915       }
916     }
917   }
918   return TRUE;
919 }