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); 79 FX_BOOL Execute() { return m_MainProc.Execute(this); } 80 FX_BOOL DoOperator(PDF_PSOP op); 81 void Reset() { m_StackCount = 0; } 82 void Push(FX_FLOAT value); 83 void Push(int value) { Push((FX_FLOAT)value); } 84 FX_FLOAT Pop(); 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 }; 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 } 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 } 136 CPDF_PSEngine::CPDF_PSEngine() { 137 m_StackCount = 0; 138 } 139 CPDF_PSEngine::~CPDF_PSEngine() {} 140 void CPDF_PSEngine::Push(FX_FLOAT v) { 141 if (m_StackCount == 100) { 142 return; 143 } 144 m_Stack[m_StackCount++] = v; 145 } 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}}; 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 } 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 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 } 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 } 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 487 CPDF_SampledFunc::CPDF_SampledFunc() { 488 m_pSampleStream = NULL; 489 m_pEncodeInfo = NULL; 490 m_pDecodeInfo = NULL; 491 } 492 CPDF_SampledFunc::~CPDF_SampledFunc() { 493 delete m_pSampleStream; 494 FX_Free(m_pEncodeInfo); 495 FX_Free(m_pDecodeInfo); 496 } 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 } 554 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 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 } 644 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 676 CPDF_ExpIntFunc::CPDF_ExpIntFunc() { 677 m_pBeginValues = NULL; 678 m_pEndValues = NULL; 679 } 680 CPDF_ExpIntFunc::~CPDF_ExpIntFunc() { 681 FX_Free(m_pBeginValues); 682 FX_Free(m_pEndValues); 683 } 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 } 711 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 738 CPDF_StitchFunc::CPDF_StitchFunc() { 739 m_pBounds = NULL; 740 m_pEncode = NULL; 741 } 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 } 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 } 809 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 } 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 } 855 CPDF_Function::CPDF_Function() { 856 m_pDomains = NULL; 857 m_pRanges = NULL; 858 } 859 CPDF_Function::~CPDF_Function() { 860 FX_Free(m_pDomains); 861 FX_Free(m_pRanges); 862 } 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 } 901 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