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