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);
Execute()79   FX_BOOL Execute() { return m_MainProc.Execute(this); }
80   FX_BOOL DoOperator(PDF_PSOP op);
Reset()81   void Reset() { m_StackCount = 0; }
82   void Push(FX_FLOAT value);
Push(int value)83   void Push(int value) { Push((FX_FLOAT)value); }
84   FX_FLOAT Pop();
GetStackSize()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 };
~CPDF_PSProc()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 }
Execute(CPDF_PSEngine * pEngine)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 }
CPDF_PSEngine()136 CPDF_PSEngine::CPDF_PSEngine() {
137   m_StackCount = 0;
138 }
~CPDF_PSEngine()139 CPDF_PSEngine::~CPDF_PSEngine() {}
Push(FX_FLOAT v)140 void CPDF_PSEngine::Push(FX_FLOAT v) {
141   if (m_StackCount == 100) {
142     return;
143   }
144   m_Stack[m_StackCount++] = v;
145 }
Pop()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}};
Parse(const FX_CHAR * string,int size)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 }
Parse(CPDF_SimpleParser & parser)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
DoOperator(PDF_PSOP op)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 }
PDF_Interpolate(FX_FLOAT x,FX_FLOAT xmin,FX_FLOAT xmax,FX_FLOAT ymin,FX_FLOAT ymax)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 }
_GetBits32(const uint8_t * pData,int bitpos,int nbits)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 
CPDF_SampledFunc()487 CPDF_SampledFunc::CPDF_SampledFunc() {
488   m_pSampleStream = NULL;
489   m_pEncodeInfo = NULL;
490   m_pDecodeInfo = NULL;
491 }
~CPDF_SampledFunc()492 CPDF_SampledFunc::~CPDF_SampledFunc() {
493   delete m_pSampleStream;
494   FX_Free(m_pEncodeInfo);
495   FX_Free(m_pDecodeInfo);
496 }
v_Init(CPDF_Object * pObj)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 }
v_Call(FX_FLOAT * inputs,FX_FLOAT * results) const554 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 
v_Init(CPDF_Object * pObj)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 }
v_Call(FX_FLOAT * inputs,FX_FLOAT * results) const644 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 
CPDF_ExpIntFunc()676 CPDF_ExpIntFunc::CPDF_ExpIntFunc() {
677   m_pBeginValues = NULL;
678   m_pEndValues = NULL;
679 }
~CPDF_ExpIntFunc()680 CPDF_ExpIntFunc::~CPDF_ExpIntFunc() {
681     FX_Free(m_pBeginValues);
682     FX_Free(m_pEndValues);
683 }
v_Init(CPDF_Object * pObj)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 }
v_Call(FX_FLOAT * inputs,FX_FLOAT * results) const711 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 
CPDF_StitchFunc()738 CPDF_StitchFunc::CPDF_StitchFunc() {
739   m_pBounds = NULL;
740   m_pEncode = NULL;
741 }
~CPDF_StitchFunc()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 }
v_Init(CPDF_Object * pObj)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 }
v_Call(FX_FLOAT * inputs,FX_FLOAT * outputs) const809 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 }
Load(CPDF_Object * pFuncObj)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 }
CPDF_Function()855 CPDF_Function::CPDF_Function() {
856   m_pDomains = NULL;
857   m_pRanges = NULL;
858 }
~CPDF_Function()859 CPDF_Function::~CPDF_Function() {
860   FX_Free(m_pDomains);
861   FX_Free(m_pRanges);
862 }
Init(CPDF_Object * pObj)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 }
Call(FX_FLOAT * inputs,int ninputs,FX_FLOAT * results,int & nresults) const901 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