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