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