• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2017 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 "core/fpdfapi/page/cpdf_psengine.h"
8 
9 #include <algorithm>
10 #include <cmath>
11 #include <limits>
12 #include <utility>
13 
14 #include "core/fpdfapi/parser/cpdf_simple_parser.h"
15 #include "core/fxcrt/fx_safe_types.h"
16 #include "core/fxcrt/fx_string.h"
17 #include "third_party/base/logging.h"
18 #include "third_party/base/ptr_util.h"
19 
20 namespace {
21 
22 struct PDF_PSOpName {
23   const char* name;
24   PDF_PSOP op;
25 };
26 
27 constexpr PDF_PSOpName kPsOpNames[] = {
28     {"abs", PSOP_ABS},
29     {"add", PSOP_ADD},
30     {"and", PSOP_AND},
31     {"atan", PSOP_ATAN},
32     {"bitshift", PSOP_BITSHIFT},
33     {"ceiling", PSOP_CEILING},
34     {"copy", PSOP_COPY},
35     {"cos", PSOP_COS},
36     {"cvi", PSOP_CVI},
37     {"cvr", PSOP_CVR},
38     {"div", PSOP_DIV},
39     {"dup", PSOP_DUP},
40     {"eq", PSOP_EQ},
41     {"exch", PSOP_EXCH},
42     {"exp", PSOP_EXP},
43     {"false", PSOP_FALSE},
44     {"floor", PSOP_FLOOR},
45     {"ge", PSOP_GE},
46     {"gt", PSOP_GT},
47     {"idiv", PSOP_IDIV},
48     {"if", PSOP_IF},
49     {"ifelse", PSOP_IFELSE},
50     {"index", PSOP_INDEX},
51     {"le", PSOP_LE},
52     {"ln", PSOP_LN},
53     {"log", PSOP_LOG},
54     {"lt", PSOP_LT},
55     {"mod", PSOP_MOD},
56     {"mul", PSOP_MUL},
57     {"ne", PSOP_NE},
58     {"neg", PSOP_NEG},
59     {"not", PSOP_NOT},
60     {"or", PSOP_OR},
61     {"pop", PSOP_POP},
62     {"roll", PSOP_ROLL},
63     {"round", PSOP_ROUND},
64     {"sin", PSOP_SIN},
65     {"sqrt", PSOP_SQRT},
66     {"sub", PSOP_SUB},
67     {"true", PSOP_TRUE},
68     {"truncate", PSOP_TRUNCATE},
69     {"xor", PSOP_XOR},
70 };
71 
72 // Round half up is a nearest integer round with half-way numbers always rounded
73 // up. Example: -5.5 rounds to -5.
RoundHalfUp(float f)74 float RoundHalfUp(float f) {
75   if (std::isnan(f))
76     return 0;
77   if (f > std::numeric_limits<float>::max() - 0.5f)
78     return std::numeric_limits<float>::max();
79   return floor(f + 0.5f);
80 }
81 
82 }  // namespace
83 
CPDF_PSOP()84 CPDF_PSOP::CPDF_PSOP()
85     : m_op(PSOP_PROC), m_value(0), m_proc(pdfium::MakeUnique<CPDF_PSProc>()) {}
86 
CPDF_PSOP(PDF_PSOP op)87 CPDF_PSOP::CPDF_PSOP(PDF_PSOP op) : m_op(op), m_value(0) {
88   ASSERT(m_op != PSOP_CONST);
89   ASSERT(m_op != PSOP_PROC);
90 }
91 
CPDF_PSOP(float value)92 CPDF_PSOP::CPDF_PSOP(float value) : m_op(PSOP_CONST), m_value(value) {}
93 
~CPDF_PSOP()94 CPDF_PSOP::~CPDF_PSOP() {}
95 
GetFloatValue() const96 float CPDF_PSOP::GetFloatValue() const {
97   if (m_op == PSOP_CONST)
98     return m_value;
99 
100   NOTREACHED();
101   return 0;
102 }
103 
GetProc() const104 CPDF_PSProc* CPDF_PSOP::GetProc() const {
105   if (m_op == PSOP_PROC)
106     return m_proc.get();
107   NOTREACHED();
108   return nullptr;
109 }
110 
Execute()111 bool CPDF_PSEngine::Execute() {
112   return m_MainProc.Execute(this);
113 }
114 
CPDF_PSProc()115 CPDF_PSProc::CPDF_PSProc() {}
~CPDF_PSProc()116 CPDF_PSProc::~CPDF_PSProc() {}
117 
Parse(CPDF_SimpleParser * parser,int depth)118 bool CPDF_PSProc::Parse(CPDF_SimpleParser* parser, int depth) {
119   if (depth > kMaxDepth)
120     return false;
121 
122   while (1) {
123     ByteStringView word = parser->GetWord();
124     if (word.IsEmpty())
125       return false;
126 
127     if (word == "}")
128       return true;
129 
130     if (word == "{") {
131       m_Operators.push_back(pdfium::MakeUnique<CPDF_PSOP>());
132       if (!m_Operators.back()->GetProc()->Parse(parser, depth + 1))
133         return false;
134       continue;
135     }
136 
137     AddOperator(word);
138   }
139 }
140 
Execute(CPDF_PSEngine * pEngine)141 bool CPDF_PSProc::Execute(CPDF_PSEngine* pEngine) {
142   for (size_t i = 0; i < m_Operators.size(); ++i) {
143     const PDF_PSOP op = m_Operators[i]->GetOp();
144     if (op == PSOP_PROC)
145       continue;
146 
147     if (op == PSOP_CONST) {
148       pEngine->Push(m_Operators[i]->GetFloatValue());
149       continue;
150     }
151 
152     if (op == PSOP_IF) {
153       if (i == 0 || m_Operators[i - 1]->GetOp() != PSOP_PROC)
154         return false;
155 
156       if (pEngine->PopInt())
157         m_Operators[i - 1]->GetProc()->Execute(pEngine);
158     } else if (op == PSOP_IFELSE) {
159       if (i < 2 || m_Operators[i - 1]->GetOp() != PSOP_PROC ||
160           m_Operators[i - 2]->GetOp() != PSOP_PROC) {
161         return false;
162       }
163       size_t offset = pEngine->PopInt() ? 2 : 1;
164       m_Operators[i - offset]->GetProc()->Execute(pEngine);
165     } else {
166       pEngine->DoOperator(op);
167     }
168   }
169   return true;
170 }
171 
AddOperatorForTesting(ByteStringView word)172 void CPDF_PSProc::AddOperatorForTesting(ByteStringView word) {
173   AddOperator(word);
174 }
175 
AddOperator(ByteStringView word)176 void CPDF_PSProc::AddOperator(ByteStringView word) {
177   const auto* pFound =
178       std::lower_bound(std::begin(kPsOpNames), std::end(kPsOpNames), word,
179                        [](const PDF_PSOpName& name, ByteStringView word) {
180                          return name.name < word;
181                        });
182   if (pFound != std::end(kPsOpNames) && pFound->name == word)
183     m_Operators.push_back(pdfium::MakeUnique<CPDF_PSOP>(pFound->op));
184   else
185     m_Operators.push_back(pdfium::MakeUnique<CPDF_PSOP>(StringToFloat(word)));
186 }
187 
188 CPDF_PSEngine::CPDF_PSEngine() = default;
189 
190 CPDF_PSEngine::~CPDF_PSEngine() = default;
191 
Push(float v)192 void CPDF_PSEngine::Push(float v) {
193   if (m_StackCount < kPSEngineStackSize)
194     m_Stack[m_StackCount++] = v;
195 }
196 
Pop()197 float CPDF_PSEngine::Pop() {
198   return m_StackCount > 0 ? m_Stack[--m_StackCount] : 0;
199 }
200 
PopInt()201 int CPDF_PSEngine::PopInt() {
202   return static_cast<int>(Pop());
203 }
204 
Parse(pdfium::span<const uint8_t> input)205 bool CPDF_PSEngine::Parse(pdfium::span<const uint8_t> input) {
206   CPDF_SimpleParser parser(input);
207   return parser.GetWord() == "{" && m_MainProc.Parse(&parser, 0);
208 }
209 
DoOperator(PDF_PSOP op)210 bool CPDF_PSEngine::DoOperator(PDF_PSOP op) {
211   int i1;
212   int i2;
213   float d1;
214   float d2;
215   FX_SAFE_INT32 result;
216   switch (op) {
217     case PSOP_ADD:
218       d1 = Pop();
219       d2 = Pop();
220       Push(d1 + d2);
221       break;
222     case PSOP_SUB:
223       d2 = Pop();
224       d1 = Pop();
225       Push(d1 - d2);
226       break;
227     case PSOP_MUL:
228       d1 = Pop();
229       d2 = Pop();
230       Push(d1 * d2);
231       break;
232     case PSOP_DIV:
233       d2 = Pop();
234       d1 = Pop();
235       Push(d1 / d2);
236       break;
237     case PSOP_IDIV:
238       i2 = PopInt();
239       i1 = PopInt();
240       if (i2) {
241         result = i1;
242         result /= i2;
243         Push(result.ValueOrDefault(0));
244       } else {
245         Push(0);
246       }
247       break;
248     case PSOP_MOD:
249       i2 = PopInt();
250       i1 = PopInt();
251       if (i2) {
252         result = i1;
253         result %= i2;
254         Push(result.ValueOrDefault(0));
255       } else {
256         Push(0);
257       }
258       break;
259     case PSOP_NEG:
260       d1 = Pop();
261       Push(-d1);
262       break;
263     case PSOP_ABS:
264       d1 = Pop();
265       Push(fabs(d1));
266       break;
267     case PSOP_CEILING:
268       d1 = Pop();
269       Push(ceil(d1));
270       break;
271     case PSOP_FLOOR:
272       d1 = Pop();
273       Push(floor(d1));
274       break;
275     case PSOP_ROUND:
276       d1 = Pop();
277       Push(RoundHalfUp(d1));
278       break;
279     case PSOP_TRUNCATE:
280       i1 = PopInt();
281       Push(i1);
282       break;
283     case PSOP_SQRT:
284       d1 = Pop();
285       Push(sqrt(d1));
286       break;
287     case PSOP_SIN:
288       d1 = Pop();
289       Push(sin(d1 * FX_PI / 180.0f));
290       break;
291     case PSOP_COS:
292       d1 = Pop();
293       Push(cos(d1 * FX_PI / 180.0f));
294       break;
295     case PSOP_ATAN:
296       d2 = Pop();
297       d1 = Pop();
298       d1 = atan2(d1, d2) * 180.0 / FX_PI;
299       if (d1 < 0) {
300         d1 += 360;
301       }
302       Push(d1);
303       break;
304     case PSOP_EXP:
305       d2 = Pop();
306       d1 = Pop();
307       Push(FXSYS_pow(d1, d2));
308       break;
309     case PSOP_LN:
310       d1 = Pop();
311       Push(log(d1));
312       break;
313     case PSOP_LOG:
314       d1 = Pop();
315       Push(log10(d1));
316       break;
317     case PSOP_CVI:
318       i1 = PopInt();
319       Push(i1);
320       break;
321     case PSOP_CVR:
322       break;
323     case PSOP_EQ:
324       d2 = Pop();
325       d1 = Pop();
326       Push(d1 == d2);
327       break;
328     case PSOP_NE:
329       d2 = Pop();
330       d1 = Pop();
331       Push(d1 != d2);
332       break;
333     case PSOP_GT:
334       d2 = Pop();
335       d1 = Pop();
336       Push(d1 > d2);
337       break;
338     case PSOP_GE:
339       d2 = Pop();
340       d1 = Pop();
341       Push(d1 >= d2);
342       break;
343     case PSOP_LT:
344       d2 = Pop();
345       d1 = Pop();
346       Push(d1 < d2);
347       break;
348     case PSOP_LE:
349       d2 = Pop();
350       d1 = Pop();
351       Push(d1 <= d2);
352       break;
353     case PSOP_AND:
354       i1 = PopInt();
355       i2 = PopInt();
356       Push(i1 & i2);
357       break;
358     case PSOP_OR:
359       i1 = PopInt();
360       i2 = PopInt();
361       Push(i1 | i2);
362       break;
363     case PSOP_XOR:
364       i1 = PopInt();
365       i2 = PopInt();
366       Push(i1 ^ i2);
367       break;
368     case PSOP_NOT:
369       i1 = PopInt();
370       Push(!i1);
371       break;
372     case PSOP_BITSHIFT: {
373       int shift = PopInt();
374       result = PopInt();
375       if (shift > 0) {
376         result <<= shift;
377       } else {
378         // Avoids unsafe negation of INT_MIN.
379         FX_SAFE_INT32 safe_shift = shift;
380         result >>= (-safe_shift).ValueOrDefault(0);
381       }
382       Push(result.ValueOrDefault(0));
383       break;
384     }
385     case PSOP_TRUE:
386       Push(1);
387       break;
388     case PSOP_FALSE:
389       Push(0);
390       break;
391     case PSOP_POP:
392       Pop();
393       break;
394     case PSOP_EXCH:
395       d2 = Pop();
396       d1 = Pop();
397       Push(d2);
398       Push(d1);
399       break;
400     case PSOP_DUP:
401       d1 = Pop();
402       Push(d1);
403       Push(d1);
404       break;
405     case PSOP_COPY: {
406       int n = PopInt();
407       if (n < 0 || m_StackCount + n > kPSEngineStackSize ||
408           n > static_cast<int>(m_StackCount))
409         break;
410       for (int i = 0; i < n; i++)
411         m_Stack[m_StackCount + i] = m_Stack[m_StackCount + i - n];
412       m_StackCount += n;
413       break;
414     }
415     case PSOP_INDEX: {
416       int n = PopInt();
417       if (n < 0 || n >= static_cast<int>(m_StackCount))
418         break;
419       Push(m_Stack[m_StackCount - n - 1]);
420       break;
421     }
422     case PSOP_ROLL: {
423       int j = PopInt();
424       int n = PopInt();
425       if (j == 0 || n == 0 || m_StackCount == 0)
426         break;
427       if (n < 0 || n > static_cast<int>(m_StackCount))
428         break;
429 
430       j %= n;
431       if (j > 0)
432         j -= n;
433       auto* begin_it = std::begin(m_Stack) + m_StackCount - n;
434       auto* middle_it = begin_it - j;
435       auto* end_it = std::begin(m_Stack) + m_StackCount;
436       std::rotate(begin_it, middle_it, end_it);
437       break;
438     }
439     default:
440       break;
441   }
442   return true;
443 }
444