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