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