1 // Copyright 2014 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/pageint.h"
8
9 #include <limits.h>
10
11 #include <algorithm>
12 #include <memory>
13 #include <utility>
14 #include <vector>
15
16 #include "core/fpdfapi/page/cpdf_psengine.h"
17 #include "core/fpdfapi/parser/cpdf_array.h"
18 #include "core/fpdfapi/parser/cpdf_dictionary.h"
19 #include "core/fpdfapi/parser/cpdf_simple_parser.h"
20 #include "core/fpdfapi/parser/cpdf_stream.h"
21 #include "core/fpdfapi/parser/cpdf_stream_acc.h"
22 #include "core/fxcrt/fx_safe_types.h"
23 #include "third_party/base/ptr_util.h"
24
25 namespace {
26
27 struct PDF_PSOpName {
28 const FX_CHAR* name;
29 PDF_PSOP op;
30 };
31
32 const PDF_PSOpName kPsOpNames[] = {
33 {"add", PSOP_ADD}, {"sub", PSOP_SUB},
34 {"mul", PSOP_MUL}, {"div", PSOP_DIV},
35 {"idiv", PSOP_IDIV}, {"mod", PSOP_MOD},
36 {"neg", PSOP_NEG}, {"abs", PSOP_ABS},
37 {"ceiling", PSOP_CEILING}, {"floor", PSOP_FLOOR},
38 {"round", PSOP_ROUND}, {"truncate", PSOP_TRUNCATE},
39 {"sqrt", PSOP_SQRT}, {"sin", PSOP_SIN},
40 {"cos", PSOP_COS}, {"atan", PSOP_ATAN},
41 {"exp", PSOP_EXP}, {"ln", PSOP_LN},
42 {"log", PSOP_LOG}, {"cvi", PSOP_CVI},
43 {"cvr", PSOP_CVR}, {"eq", PSOP_EQ},
44 {"ne", PSOP_NE}, {"gt", PSOP_GT},
45 {"ge", PSOP_GE}, {"lt", PSOP_LT},
46 {"le", PSOP_LE}, {"and", PSOP_AND},
47 {"or", PSOP_OR}, {"xor", PSOP_XOR},
48 {"not", PSOP_NOT}, {"bitshift", PSOP_BITSHIFT},
49 {"true", PSOP_TRUE}, {"false", PSOP_FALSE},
50 {"if", PSOP_IF}, {"ifelse", PSOP_IFELSE},
51 {"pop", PSOP_POP}, {"exch", PSOP_EXCH},
52 {"dup", PSOP_DUP}, {"copy", PSOP_COPY},
53 {"index", PSOP_INDEX}, {"roll", PSOP_ROLL}};
54
55 // See PDF Reference 1.7, page 170, table 3.36.
IsValidBitsPerSample(uint32_t x)56 bool IsValidBitsPerSample(uint32_t x) {
57 switch (x) {
58 case 1:
59 case 2:
60 case 4:
61 case 8:
62 case 12:
63 case 16:
64 case 24:
65 case 32:
66 return true;
67 default:
68 return false;
69 }
70 }
71
72 // See PDF Reference 1.7, page 170.
PDF_Interpolate(FX_FLOAT x,FX_FLOAT xmin,FX_FLOAT xmax,FX_FLOAT ymin,FX_FLOAT ymax)73 FX_FLOAT PDF_Interpolate(FX_FLOAT x,
74 FX_FLOAT xmin,
75 FX_FLOAT xmax,
76 FX_FLOAT ymin,
77 FX_FLOAT ymax) {
78 FX_FLOAT divisor = xmax - xmin;
79 return ymin + (divisor ? (x - xmin) * (ymax - ymin) / divisor : 0);
80 }
81
82 class CPDF_PSFunc : public CPDF_Function {
83 public:
CPDF_PSFunc()84 CPDF_PSFunc() : CPDF_Function(Type::kType4PostScript) {}
~CPDF_PSFunc()85 ~CPDF_PSFunc() override {}
86
87 // CPDF_Function
88 bool v_Init(CPDF_Object* pObj) override;
89 bool v_Call(FX_FLOAT* inputs, FX_FLOAT* results) const override;
90
91 private:
92 CPDF_PSEngine m_PS;
93 };
94
v_Init(CPDF_Object * pObj)95 bool CPDF_PSFunc::v_Init(CPDF_Object* pObj) {
96 CPDF_StreamAcc acc;
97 acc.LoadAllData(pObj->AsStream(), false);
98 return m_PS.Parse(reinterpret_cast<const FX_CHAR*>(acc.GetData()),
99 acc.GetSize());
100 }
101
v_Call(FX_FLOAT * inputs,FX_FLOAT * results) const102 bool CPDF_PSFunc::v_Call(FX_FLOAT* inputs, FX_FLOAT* results) const {
103 CPDF_PSEngine& PS = const_cast<CPDF_PSEngine&>(m_PS);
104 PS.Reset();
105 for (uint32_t i = 0; i < m_nInputs; i++)
106 PS.Push(inputs[i]);
107 PS.Execute();
108 if (PS.GetStackSize() < m_nOutputs)
109 return false;
110 for (uint32_t i = 0; i < m_nOutputs; i++)
111 results[m_nOutputs - i - 1] = PS.Pop();
112 return true;
113 }
114
115 } // namespace
116
117 class CPDF_PSOP {
118 public:
CPDF_PSOP(PDF_PSOP op)119 explicit CPDF_PSOP(PDF_PSOP op) : m_op(op), m_value(0) {
120 ASSERT(m_op != PSOP_CONST);
121 ASSERT(m_op != PSOP_PROC);
122 }
CPDF_PSOP(FX_FLOAT value)123 explicit CPDF_PSOP(FX_FLOAT value) : m_op(PSOP_CONST), m_value(value) {}
CPDF_PSOP(std::unique_ptr<CPDF_PSProc> proc)124 explicit CPDF_PSOP(std::unique_ptr<CPDF_PSProc> proc)
125 : m_op(PSOP_PROC), m_value(0), m_proc(std::move(proc)) {}
126
GetFloatValue() const127 FX_FLOAT GetFloatValue() const {
128 if (m_op == PSOP_CONST)
129 return m_value;
130
131 ASSERT(false);
132 return 0;
133 }
GetProc() const134 CPDF_PSProc* GetProc() const {
135 if (m_op == PSOP_PROC)
136 return m_proc.get();
137 ASSERT(false);
138 return nullptr;
139 }
140
GetOp() const141 PDF_PSOP GetOp() const { return m_op; }
142
143 private:
144 const PDF_PSOP m_op;
145 const FX_FLOAT m_value;
146 std::unique_ptr<CPDF_PSProc> m_proc;
147 };
148
Execute()149 bool CPDF_PSEngine::Execute() {
150 return m_MainProc.Execute(this);
151 }
152
CPDF_PSProc()153 CPDF_PSProc::CPDF_PSProc() {}
~CPDF_PSProc()154 CPDF_PSProc::~CPDF_PSProc() {}
155
Execute(CPDF_PSEngine * pEngine)156 bool CPDF_PSProc::Execute(CPDF_PSEngine* pEngine) {
157 for (size_t i = 0; i < m_Operators.size(); ++i) {
158 const PDF_PSOP op = m_Operators[i]->GetOp();
159 if (op == PSOP_PROC)
160 continue;
161
162 if (op == PSOP_CONST) {
163 pEngine->Push(m_Operators[i]->GetFloatValue());
164 continue;
165 }
166
167 if (op == PSOP_IF) {
168 if (i == 0 || m_Operators[i - 1]->GetOp() != PSOP_PROC)
169 return false;
170
171 if (static_cast<int>(pEngine->Pop()))
172 m_Operators[i - 1]->GetProc()->Execute(pEngine);
173 } else if (op == PSOP_IFELSE) {
174 if (i < 2 || m_Operators[i - 1]->GetOp() != PSOP_PROC ||
175 m_Operators[i - 2]->GetOp() != PSOP_PROC) {
176 return false;
177 }
178 size_t offset = static_cast<int>(pEngine->Pop()) ? 2 : 1;
179 m_Operators[i - offset]->GetProc()->Execute(pEngine);
180 } else {
181 pEngine->DoOperator(op);
182 }
183 }
184 return true;
185 }
186
CPDF_PSEngine()187 CPDF_PSEngine::CPDF_PSEngine() {
188 m_StackCount = 0;
189 }
~CPDF_PSEngine()190 CPDF_PSEngine::~CPDF_PSEngine() {}
Push(FX_FLOAT v)191 void CPDF_PSEngine::Push(FX_FLOAT v) {
192 if (m_StackCount == PSENGINE_STACKSIZE) {
193 return;
194 }
195 m_Stack[m_StackCount++] = v;
196 }
Pop()197 FX_FLOAT CPDF_PSEngine::Pop() {
198 if (m_StackCount == 0) {
199 return 0;
200 }
201 return m_Stack[--m_StackCount];
202 }
Parse(const FX_CHAR * str,int size)203 bool CPDF_PSEngine::Parse(const FX_CHAR* str, int size) {
204 CPDF_SimpleParser parser((uint8_t*)str, size);
205 CFX_ByteStringC word = parser.GetWord();
206 if (word != "{") {
207 return false;
208 }
209 return m_MainProc.Parse(&parser, 0);
210 }
211
Parse(CPDF_SimpleParser * parser,int depth)212 bool CPDF_PSProc::Parse(CPDF_SimpleParser* parser, int depth) {
213 if (depth > kMaxDepth)
214 return false;
215
216 while (1) {
217 CFX_ByteStringC word = parser->GetWord();
218 if (word.IsEmpty()) {
219 return false;
220 }
221 if (word == "}") {
222 return true;
223 }
224 if (word == "{") {
225 std::unique_ptr<CPDF_PSProc> proc(new CPDF_PSProc);
226 std::unique_ptr<CPDF_PSOP> op(new CPDF_PSOP(std::move(proc)));
227 m_Operators.push_back(std::move(op));
228 if (!m_Operators.back()->GetProc()->Parse(parser, depth + 1)) {
229 return false;
230 }
231 } else {
232 bool found = false;
233 for (const PDF_PSOpName& op_name : kPsOpNames) {
234 if (word == CFX_ByteStringC(op_name.name)) {
235 std::unique_ptr<CPDF_PSOP> op(new CPDF_PSOP(op_name.op));
236 m_Operators.push_back(std::move(op));
237 found = true;
238 break;
239 }
240 }
241 if (!found) {
242 std::unique_ptr<CPDF_PSOP> op(new CPDF_PSOP(FX_atof(word)));
243 m_Operators.push_back(std::move(op));
244 }
245 }
246 }
247 }
248
DoOperator(PDF_PSOP op)249 bool CPDF_PSEngine::DoOperator(PDF_PSOP op) {
250 int i1;
251 int i2;
252 FX_FLOAT d1;
253 FX_FLOAT d2;
254 FX_SAFE_INT32 result;
255 switch (op) {
256 case PSOP_ADD:
257 d1 = Pop();
258 d2 = Pop();
259 Push(d1 + d2);
260 break;
261 case PSOP_SUB:
262 d2 = Pop();
263 d1 = Pop();
264 Push(d1 - d2);
265 break;
266 case PSOP_MUL:
267 d1 = Pop();
268 d2 = Pop();
269 Push(d1 * d2);
270 break;
271 case PSOP_DIV:
272 d2 = Pop();
273 d1 = Pop();
274 Push(d1 / d2);
275 break;
276 case PSOP_IDIV:
277 i2 = static_cast<int>(Pop());
278 i1 = static_cast<int>(Pop());
279 if (i2) {
280 result = i1;
281 result /= i2;
282 Push(result.ValueOrDefault(0));
283 } else {
284 Push(0);
285 }
286 break;
287 case PSOP_MOD:
288 i2 = static_cast<int>(Pop());
289 i1 = static_cast<int>(Pop());
290 if (i2) {
291 result = i1;
292 result %= i2;
293 Push(result.ValueOrDefault(0));
294 } else {
295 Push(0);
296 }
297 break;
298 case PSOP_NEG:
299 d1 = Pop();
300 Push(-d1);
301 break;
302 case PSOP_ABS:
303 d1 = Pop();
304 Push((FX_FLOAT)FXSYS_fabs(d1));
305 break;
306 case PSOP_CEILING:
307 d1 = Pop();
308 Push((FX_FLOAT)FXSYS_ceil(d1));
309 break;
310 case PSOP_FLOOR:
311 d1 = Pop();
312 Push((FX_FLOAT)FXSYS_floor(d1));
313 break;
314 case PSOP_ROUND:
315 d1 = Pop();
316 Push(FXSYS_round(d1));
317 break;
318 case PSOP_TRUNCATE:
319 i1 = (int)Pop();
320 Push(i1);
321 break;
322 case PSOP_SQRT:
323 d1 = Pop();
324 Push((FX_FLOAT)FXSYS_sqrt(d1));
325 break;
326 case PSOP_SIN:
327 d1 = Pop();
328 Push((FX_FLOAT)FXSYS_sin(d1 * FX_PI / 180.0f));
329 break;
330 case PSOP_COS:
331 d1 = Pop();
332 Push((FX_FLOAT)FXSYS_cos(d1 * FX_PI / 180.0f));
333 break;
334 case PSOP_ATAN:
335 d2 = Pop();
336 d1 = Pop();
337 d1 = (FX_FLOAT)(FXSYS_atan2(d1, d2) * 180.0 / FX_PI);
338 if (d1 < 0) {
339 d1 += 360;
340 }
341 Push(d1);
342 break;
343 case PSOP_EXP:
344 d2 = Pop();
345 d1 = Pop();
346 Push((FX_FLOAT)FXSYS_pow(d1, d2));
347 break;
348 case PSOP_LN:
349 d1 = Pop();
350 Push((FX_FLOAT)FXSYS_log(d1));
351 break;
352 case PSOP_LOG:
353 d1 = Pop();
354 Push((FX_FLOAT)FXSYS_log10(d1));
355 break;
356 case PSOP_CVI:
357 i1 = (int)Pop();
358 Push(i1);
359 break;
360 case PSOP_CVR:
361 break;
362 case PSOP_EQ:
363 d2 = Pop();
364 d1 = Pop();
365 Push((int)(d1 == d2));
366 break;
367 case PSOP_NE:
368 d2 = Pop();
369 d1 = Pop();
370 Push((int)(d1 != d2));
371 break;
372 case PSOP_GT:
373 d2 = Pop();
374 d1 = Pop();
375 Push((int)(d1 > d2));
376 break;
377 case PSOP_GE:
378 d2 = Pop();
379 d1 = Pop();
380 Push((int)(d1 >= d2));
381 break;
382 case PSOP_LT:
383 d2 = Pop();
384 d1 = Pop();
385 Push((int)(d1 < d2));
386 break;
387 case PSOP_LE:
388 d2 = Pop();
389 d1 = Pop();
390 Push((int)(d1 <= d2));
391 break;
392 case PSOP_AND:
393 i1 = (int)Pop();
394 i2 = (int)Pop();
395 Push(i1 & i2);
396 break;
397 case PSOP_OR:
398 i1 = (int)Pop();
399 i2 = (int)Pop();
400 Push(i1 | i2);
401 break;
402 case PSOP_XOR:
403 i1 = (int)Pop();
404 i2 = (int)Pop();
405 Push(i1 ^ i2);
406 break;
407 case PSOP_NOT:
408 i1 = (int)Pop();
409 Push((int)!i1);
410 break;
411 case PSOP_BITSHIFT: {
412 int shift = (int)Pop();
413 result = (int)Pop();
414 if (shift > 0) {
415 result <<= shift;
416 } else {
417 // Avoids unsafe negation of INT_MIN.
418 FX_SAFE_INT32 safe_shift = shift;
419 result >>= (-safe_shift).ValueOrDefault(0);
420 }
421 Push(result.ValueOrDefault(0));
422 break;
423 }
424 case PSOP_TRUE:
425 Push(1);
426 break;
427 case PSOP_FALSE:
428 Push(0);
429 break;
430 case PSOP_POP:
431 Pop();
432 break;
433 case PSOP_EXCH:
434 d2 = Pop();
435 d1 = Pop();
436 Push(d2);
437 Push(d1);
438 break;
439 case PSOP_DUP:
440 d1 = Pop();
441 Push(d1);
442 Push(d1);
443 break;
444 case PSOP_COPY: {
445 int n = static_cast<int>(Pop());
446 if (n < 0 || m_StackCount + n > PSENGINE_STACKSIZE ||
447 n > static_cast<int>(m_StackCount))
448 break;
449 for (int i = 0; i < n; i++)
450 m_Stack[m_StackCount + i] = m_Stack[m_StackCount + i - n];
451 m_StackCount += n;
452 break;
453 }
454 case PSOP_INDEX: {
455 int n = static_cast<int>(Pop());
456 if (n < 0 || n >= static_cast<int>(m_StackCount))
457 break;
458 Push(m_Stack[m_StackCount - n - 1]);
459 break;
460 }
461 case PSOP_ROLL: {
462 int j = static_cast<int>(Pop());
463 int n = static_cast<int>(Pop());
464 if (j == 0 || n == 0 || m_StackCount == 0)
465 break;
466 if (n < 0 || n > static_cast<int>(m_StackCount))
467 break;
468
469 j %= n;
470 if (j > 0)
471 j -= n;
472 auto begin_it = std::begin(m_Stack) + m_StackCount - n;
473 auto middle_it = begin_it - j;
474 auto end_it = std::begin(m_Stack) + m_StackCount;
475 std::rotate(begin_it, middle_it, end_it);
476 break;
477 }
478 default:
479 break;
480 }
481 return true;
482 }
483
CPDF_SampledFunc()484 CPDF_SampledFunc::CPDF_SampledFunc() : CPDF_Function(Type::kType0Sampled) {}
485
~CPDF_SampledFunc()486 CPDF_SampledFunc::~CPDF_SampledFunc() {}
487
v_Init(CPDF_Object * pObj)488 bool CPDF_SampledFunc::v_Init(CPDF_Object* pObj) {
489 CPDF_Stream* pStream = pObj->AsStream();
490 if (!pStream)
491 return false;
492
493 CPDF_Dictionary* pDict = pStream->GetDict();
494 CPDF_Array* pSize = pDict->GetArrayFor("Size");
495 CPDF_Array* pEncode = pDict->GetArrayFor("Encode");
496 CPDF_Array* pDecode = pDict->GetArrayFor("Decode");
497 m_nBitsPerSample = pDict->GetIntegerFor("BitsPerSample");
498 if (!IsValidBitsPerSample(m_nBitsPerSample))
499 return false;
500
501 m_SampleMax = 0xffffffff >> (32 - m_nBitsPerSample);
502 m_pSampleStream = pdfium::MakeUnique<CPDF_StreamAcc>();
503 m_pSampleStream->LoadAllData(pStream, false);
504 FX_SAFE_UINT32 nTotalSampleBits = 1;
505 m_EncodeInfo.resize(m_nInputs);
506 for (uint32_t i = 0; i < m_nInputs; i++) {
507 m_EncodeInfo[i].sizes = pSize ? pSize->GetIntegerAt(i) : 0;
508 if (!pSize && i == 0)
509 m_EncodeInfo[i].sizes = pDict->GetIntegerFor("Size");
510 nTotalSampleBits *= m_EncodeInfo[i].sizes;
511 if (pEncode) {
512 m_EncodeInfo[i].encode_min = pEncode->GetFloatAt(i * 2);
513 m_EncodeInfo[i].encode_max = pEncode->GetFloatAt(i * 2 + 1);
514 } else {
515 m_EncodeInfo[i].encode_min = 0;
516 m_EncodeInfo[i].encode_max =
517 m_EncodeInfo[i].sizes == 1 ? 1 : (FX_FLOAT)m_EncodeInfo[i].sizes - 1;
518 }
519 }
520 nTotalSampleBits *= m_nBitsPerSample;
521 nTotalSampleBits *= m_nOutputs;
522 FX_SAFE_UINT32 nTotalSampleBytes = nTotalSampleBits;
523 nTotalSampleBytes += 7;
524 nTotalSampleBytes /= 8;
525 if (!nTotalSampleBytes.IsValid() || nTotalSampleBytes.ValueOrDie() == 0 ||
526 nTotalSampleBytes.ValueOrDie() > m_pSampleStream->GetSize()) {
527 return false;
528 }
529 m_DecodeInfo.resize(m_nOutputs);
530 for (uint32_t i = 0; i < m_nOutputs; i++) {
531 if (pDecode) {
532 m_DecodeInfo[i].decode_min = pDecode->GetFloatAt(2 * i);
533 m_DecodeInfo[i].decode_max = pDecode->GetFloatAt(2 * i + 1);
534 } else {
535 m_DecodeInfo[i].decode_min = m_pRanges[i * 2];
536 m_DecodeInfo[i].decode_max = m_pRanges[i * 2 + 1];
537 }
538 }
539 return true;
540 }
541
v_Call(FX_FLOAT * inputs,FX_FLOAT * results) const542 bool CPDF_SampledFunc::v_Call(FX_FLOAT* inputs, FX_FLOAT* results) const {
543 int pos = 0;
544 CFX_FixedBufGrow<FX_FLOAT, 16> encoded_input_buf(m_nInputs);
545 FX_FLOAT* encoded_input = encoded_input_buf;
546 CFX_FixedBufGrow<uint32_t, 32> int_buf(m_nInputs * 2);
547 uint32_t* index = int_buf;
548 uint32_t* blocksize = index + m_nInputs;
549 for (uint32_t i = 0; i < m_nInputs; i++) {
550 if (i == 0)
551 blocksize[i] = 1;
552 else
553 blocksize[i] = blocksize[i - 1] * m_EncodeInfo[i - 1].sizes;
554 encoded_input[i] =
555 PDF_Interpolate(inputs[i], m_pDomains[i * 2], m_pDomains[i * 2 + 1],
556 m_EncodeInfo[i].encode_min, m_EncodeInfo[i].encode_max);
557 index[i] = std::min((uint32_t)std::max(0.f, encoded_input[i]),
558 m_EncodeInfo[i].sizes - 1);
559 pos += index[i] * blocksize[i];
560 }
561 FX_SAFE_INT32 bits_to_output = m_nOutputs;
562 bits_to_output *= m_nBitsPerSample;
563 if (!bits_to_output.IsValid())
564 return false;
565
566 FX_SAFE_INT32 bitpos = pos;
567 bitpos *= bits_to_output.ValueOrDie();
568 if (!bitpos.IsValid())
569 return false;
570
571 FX_SAFE_INT32 range_check = bitpos;
572 range_check += bits_to_output.ValueOrDie();
573 if (!range_check.IsValid())
574 return false;
575
576 const uint8_t* pSampleData = m_pSampleStream->GetData();
577 if (!pSampleData)
578 return false;
579
580 for (uint32_t j = 0; j < m_nOutputs; j++, bitpos += m_nBitsPerSample) {
581 uint32_t sample =
582 GetBits32(pSampleData, bitpos.ValueOrDie(), m_nBitsPerSample);
583 FX_FLOAT encoded = (FX_FLOAT)sample;
584 for (uint32_t i = 0; i < m_nInputs; i++) {
585 if (index[i] == m_EncodeInfo[i].sizes - 1) {
586 if (index[i] == 0)
587 encoded = encoded_input[i] * (FX_FLOAT)sample;
588 } else {
589 FX_SAFE_INT32 bitpos2 = blocksize[i];
590 bitpos2 += pos;
591 bitpos2 *= m_nOutputs;
592 bitpos2 += j;
593 bitpos2 *= m_nBitsPerSample;
594 if (!bitpos2.IsValid())
595 return false;
596 uint32_t sample1 =
597 GetBits32(pSampleData, bitpos2.ValueOrDie(), m_nBitsPerSample);
598 encoded += (encoded_input[i] - index[i]) *
599 ((FX_FLOAT)sample1 - (FX_FLOAT)sample);
600 }
601 }
602 results[j] =
603 PDF_Interpolate(encoded, 0, (FX_FLOAT)m_SampleMax,
604 m_DecodeInfo[j].decode_min, m_DecodeInfo[j].decode_max);
605 }
606 return true;
607 }
608
CPDF_ExpIntFunc()609 CPDF_ExpIntFunc::CPDF_ExpIntFunc()
610 : CPDF_Function(Type::kType2ExpotentialInterpolation),
611 m_pBeginValues(nullptr),
612 m_pEndValues(nullptr) {}
613
~CPDF_ExpIntFunc()614 CPDF_ExpIntFunc::~CPDF_ExpIntFunc() {
615 FX_Free(m_pBeginValues);
616 FX_Free(m_pEndValues);
617 }
v_Init(CPDF_Object * pObj)618 bool CPDF_ExpIntFunc::v_Init(CPDF_Object* pObj) {
619 CPDF_Dictionary* pDict = pObj->GetDict();
620 if (!pDict) {
621 return false;
622 }
623 CPDF_Array* pArray0 = pDict->GetArrayFor("C0");
624 if (m_nOutputs == 0) {
625 m_nOutputs = 1;
626 if (pArray0) {
627 m_nOutputs = pArray0->GetCount();
628 }
629 }
630 CPDF_Array* pArray1 = pDict->GetArrayFor("C1");
631 m_pBeginValues = FX_Alloc2D(FX_FLOAT, m_nOutputs, 2);
632 m_pEndValues = FX_Alloc2D(FX_FLOAT, m_nOutputs, 2);
633 for (uint32_t i = 0; i < m_nOutputs; i++) {
634 m_pBeginValues[i] = pArray0 ? pArray0->GetFloatAt(i) : 0.0f;
635 m_pEndValues[i] = pArray1 ? pArray1->GetFloatAt(i) : 1.0f;
636 }
637 m_Exponent = pDict->GetFloatFor("N");
638 m_nOrigOutputs = m_nOutputs;
639 if (m_nOutputs && m_nInputs > INT_MAX / m_nOutputs) {
640 return false;
641 }
642 m_nOutputs *= m_nInputs;
643 return true;
644 }
v_Call(FX_FLOAT * inputs,FX_FLOAT * results) const645 bool CPDF_ExpIntFunc::v_Call(FX_FLOAT* inputs, FX_FLOAT* results) const {
646 for (uint32_t i = 0; i < m_nInputs; i++)
647 for (uint32_t j = 0; j < m_nOrigOutputs; j++) {
648 results[i * m_nOrigOutputs + j] =
649 m_pBeginValues[j] +
650 (FX_FLOAT)FXSYS_pow(inputs[i], m_Exponent) *
651 (m_pEndValues[j] - m_pBeginValues[j]);
652 }
653 return true;
654 }
655
CPDF_StitchFunc()656 CPDF_StitchFunc::CPDF_StitchFunc()
657 : CPDF_Function(Type::kType3Stitching),
658 m_pBounds(nullptr),
659 m_pEncode(nullptr) {}
660
~CPDF_StitchFunc()661 CPDF_StitchFunc::~CPDF_StitchFunc() {
662 FX_Free(m_pBounds);
663 FX_Free(m_pEncode);
664 }
665
v_Init(CPDF_Object * pObj)666 bool CPDF_StitchFunc::v_Init(CPDF_Object* pObj) {
667 CPDF_Dictionary* pDict = pObj->GetDict();
668 if (!pDict) {
669 return false;
670 }
671 if (m_nInputs != kRequiredNumInputs) {
672 return false;
673 }
674 CPDF_Array* pArray = pDict->GetArrayFor("Functions");
675 if (!pArray) {
676 return false;
677 }
678 uint32_t nSubs = pArray->GetCount();
679 if (nSubs == 0)
680 return false;
681 m_nOutputs = 0;
682 for (uint32_t i = 0; i < nSubs; i++) {
683 CPDF_Object* pSub = pArray->GetDirectObjectAt(i);
684 if (pSub == pObj)
685 return false;
686 std::unique_ptr<CPDF_Function> pFunc(CPDF_Function::Load(pSub));
687 if (!pFunc)
688 return false;
689 // Check that the input dimensionality is 1, and that all output
690 // dimensionalities are the same.
691 if (pFunc->CountInputs() != kRequiredNumInputs)
692 return false;
693 if (pFunc->CountOutputs() != m_nOutputs) {
694 if (m_nOutputs)
695 return false;
696
697 m_nOutputs = pFunc->CountOutputs();
698 }
699
700 m_pSubFunctions.push_back(std::move(pFunc));
701 }
702 m_pBounds = FX_Alloc(FX_FLOAT, nSubs + 1);
703 m_pBounds[0] = m_pDomains[0];
704 pArray = pDict->GetArrayFor("Bounds");
705 if (!pArray)
706 return false;
707 for (uint32_t i = 0; i < nSubs - 1; i++)
708 m_pBounds[i + 1] = pArray->GetFloatAt(i);
709 m_pBounds[nSubs] = m_pDomains[1];
710 m_pEncode = FX_Alloc2D(FX_FLOAT, nSubs, 2);
711 pArray = pDict->GetArrayFor("Encode");
712 if (!pArray)
713 return false;
714
715 for (uint32_t i = 0; i < nSubs * 2; i++)
716 m_pEncode[i] = pArray->GetFloatAt(i);
717 return true;
718 }
719
v_Call(FX_FLOAT * inputs,FX_FLOAT * outputs) const720 bool CPDF_StitchFunc::v_Call(FX_FLOAT* inputs, FX_FLOAT* outputs) const {
721 FX_FLOAT input = inputs[0];
722 size_t i;
723 for (i = 0; i < m_pSubFunctions.size() - 1; i++) {
724 if (input < m_pBounds[i + 1])
725 break;
726 }
727 input = PDF_Interpolate(input, m_pBounds[i], m_pBounds[i + 1],
728 m_pEncode[i * 2], m_pEncode[i * 2 + 1]);
729 int nresults;
730 m_pSubFunctions[i]->Call(&input, kRequiredNumInputs, outputs, nresults);
731 return true;
732 }
733
734 // static
Load(CPDF_Object * pFuncObj)735 std::unique_ptr<CPDF_Function> CPDF_Function::Load(CPDF_Object* pFuncObj) {
736 std::unique_ptr<CPDF_Function> pFunc;
737 if (!pFuncObj)
738 return pFunc;
739
740 int iType = -1;
741 if (CPDF_Stream* pStream = pFuncObj->AsStream())
742 iType = pStream->GetDict()->GetIntegerFor("FunctionType");
743 else if (CPDF_Dictionary* pDict = pFuncObj->AsDictionary())
744 iType = pDict->GetIntegerFor("FunctionType");
745
746 Type type = IntegerToFunctionType(iType);
747 if (type == Type::kType0Sampled)
748 pFunc = pdfium::MakeUnique<CPDF_SampledFunc>();
749 else if (type == Type::kType2ExpotentialInterpolation)
750 pFunc = pdfium::MakeUnique<CPDF_ExpIntFunc>();
751 else if (type == Type::kType3Stitching)
752 pFunc = pdfium::MakeUnique<CPDF_StitchFunc>();
753 else if (type == Type::kType4PostScript)
754 pFunc = pdfium::MakeUnique<CPDF_PSFunc>();
755
756 if (!pFunc || !pFunc->Init(pFuncObj))
757 return nullptr;
758
759 return pFunc;
760 }
761
762 // static
IntegerToFunctionType(int iType)763 CPDF_Function::Type CPDF_Function::IntegerToFunctionType(int iType) {
764 switch (iType) {
765 case 0:
766 case 2:
767 case 3:
768 case 4:
769 return static_cast<Type>(iType);
770 default:
771 return Type::kTypeInvalid;
772 }
773 }
774
CPDF_Function(Type type)775 CPDF_Function::CPDF_Function(Type type)
776 : m_pDomains(nullptr), m_pRanges(nullptr), m_Type(type) {}
777
~CPDF_Function()778 CPDF_Function::~CPDF_Function() {
779 FX_Free(m_pDomains);
780 FX_Free(m_pRanges);
781 }
782
Init(CPDF_Object * pObj)783 bool CPDF_Function::Init(CPDF_Object* pObj) {
784 CPDF_Stream* pStream = pObj->AsStream();
785 CPDF_Dictionary* pDict = pStream ? pStream->GetDict() : pObj->AsDictionary();
786
787 CPDF_Array* pDomains = pDict->GetArrayFor("Domain");
788 if (!pDomains)
789 return false;
790
791 m_nInputs = pDomains->GetCount() / 2;
792 if (m_nInputs == 0)
793 return false;
794
795 m_pDomains = FX_Alloc2D(FX_FLOAT, m_nInputs, 2);
796 for (uint32_t i = 0; i < m_nInputs * 2; i++) {
797 m_pDomains[i] = pDomains->GetFloatAt(i);
798 }
799 CPDF_Array* pRanges = pDict->GetArrayFor("Range");
800 m_nOutputs = 0;
801 if (pRanges) {
802 m_nOutputs = pRanges->GetCount() / 2;
803 m_pRanges = FX_Alloc2D(FX_FLOAT, m_nOutputs, 2);
804 for (uint32_t i = 0; i < m_nOutputs * 2; i++)
805 m_pRanges[i] = pRanges->GetFloatAt(i);
806 }
807 uint32_t old_outputs = m_nOutputs;
808 if (!v_Init(pObj))
809 return false;
810 if (m_pRanges && m_nOutputs > old_outputs) {
811 m_pRanges = FX_Realloc(FX_FLOAT, m_pRanges, m_nOutputs * 2);
812 if (m_pRanges) {
813 FXSYS_memset(m_pRanges + (old_outputs * 2), 0,
814 sizeof(FX_FLOAT) * (m_nOutputs - old_outputs) * 2);
815 }
816 }
817 return true;
818 }
819
Call(FX_FLOAT * inputs,uint32_t ninputs,FX_FLOAT * results,int & nresults) const820 bool CPDF_Function::Call(FX_FLOAT* inputs,
821 uint32_t ninputs,
822 FX_FLOAT* results,
823 int& nresults) const {
824 if (m_nInputs != ninputs) {
825 return false;
826 }
827 nresults = m_nOutputs;
828 for (uint32_t i = 0; i < m_nInputs; i++) {
829 if (inputs[i] < m_pDomains[i * 2])
830 inputs[i] = m_pDomains[i * 2];
831 else if (inputs[i] > m_pDomains[i * 2 + 1])
832 inputs[i] = m_pDomains[i * 2] + 1;
833 }
834 v_Call(inputs, results);
835 if (m_pRanges) {
836 for (uint32_t i = 0; i < m_nOutputs; i++) {
837 if (results[i] < m_pRanges[i * 2])
838 results[i] = m_pRanges[i * 2];
839 else if (results[i] > m_pRanges[i * 2 + 1])
840 results[i] = m_pRanges[i * 2 + 1];
841 }
842 }
843 return true;
844 }
845
ToSampledFunc() const846 const CPDF_SampledFunc* CPDF_Function::ToSampledFunc() const {
847 return m_Type == Type::kType0Sampled
848 ? static_cast<const CPDF_SampledFunc*>(this)
849 : nullptr;
850 }
851
ToExpIntFunc() const852 const CPDF_ExpIntFunc* CPDF_Function::ToExpIntFunc() const {
853 return m_Type == Type::kType2ExpotentialInterpolation
854 ? static_cast<const CPDF_ExpIntFunc*>(this)
855 : nullptr;
856 }
857
ToStitchFunc() const858 const CPDF_StitchFunc* CPDF_Function::ToStitchFunc() const {
859 return m_Type == Type::kType3Stitching
860 ? static_cast<const CPDF_StitchFunc*>(this)
861 : nullptr;
862 }
863