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
19class CPDF_PSEngine;
20typedef 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;
66class 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
74class 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};
92CPDF_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}
104FX_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}
136CPDF_PSEngine::CPDF_PSEngine() {
137  m_StackCount = 0;
138}
139CPDF_PSEngine::~CPDF_PSEngine() {}
140void CPDF_PSEngine::Push(FX_FLOAT v) {
141  if (m_StackCount == 100) {
142    return;
143  }
144  m_Stack[m_StackCount++] = v;
145}
146FX_FLOAT CPDF_PSEngine::Pop() {
147  if (m_StackCount == 0) {
148    return 0;
149  }
150  return m_Stack[--m_StackCount];
151}
152const 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}};
177FX_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}
185FX_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
220FX_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}
450static 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}
457static 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}
465typedef struct {
466  FX_FLOAT encode_max, encode_min;
467  int sizes;
468} SampleEncodeInfo;
469typedef struct { FX_FLOAT decode_max, decode_min; } SampleDecodeInfo;
470
471class 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
487CPDF_SampledFunc::CPDF_SampledFunc() {
488  m_pSampleStream = NULL;
489  m_pEncodeInfo = NULL;
490  m_pDecodeInfo = NULL;
491}
492CPDF_SampledFunc::~CPDF_SampledFunc() {
493  delete m_pSampleStream;
494  FX_Free(m_pEncodeInfo);
495  FX_Free(m_pDecodeInfo);
496}
497FX_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}
554FX_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
629class 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
638FX_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}
644FX_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
661class 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
676CPDF_ExpIntFunc::CPDF_ExpIntFunc() {
677  m_pBeginValues = NULL;
678  m_pEndValues = NULL;
679}
680CPDF_ExpIntFunc::~CPDF_ExpIntFunc() {
681    FX_Free(m_pBeginValues);
682    FX_Free(m_pEndValues);
683}
684FX_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}
711FX_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
722class 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
738CPDF_StitchFunc::CPDF_StitchFunc() {
739  m_pBounds = NULL;
740  m_pEncode = NULL;
741}
742CPDF_StitchFunc::~CPDF_StitchFunc() {
743  for (auto& sub : m_pSubFunctions) {
744    delete sub;
745  }
746  FX_Free(m_pBounds);
747  FX_Free(m_pEncode);
748}
749FX_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}
809FX_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}
825CPDF_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}
855CPDF_Function::CPDF_Function() {
856  m_pDomains = NULL;
857  m_pRanges = NULL;
858}
859CPDF_Function::~CPDF_Function() {
860  FX_Free(m_pDomains);
861  FX_Free(m_pRanges);
862}
863FX_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}
901FX_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