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