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