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