1 // Copyright 2017 PDFium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6 
7 #include "core/fpdfapi/page/cpdf_sampledfunc.h"
8 
9 #include "core/fpdfapi/parser/cpdf_array.h"
10 #include "core/fxcrt/cfx_fixedbufgrow.h"
11 #include "core/fxcrt/fx_extension.h"
12 #include "core/fxcrt/fx_safe_types.h"
13 
14 namespace {
15 
16 // See PDF Reference 1.7, page 170, table 3.36.
IsValidBitsPerSample(uint32_t x)17 bool IsValidBitsPerSample(uint32_t x) {
18   switch (x) {
19     case 1:
20     case 2:
21     case 4:
22     case 8:
23     case 12:
24     case 16:
25     case 24:
26     case 32:
27       return true;
28     default:
29       return false;
30   }
31 }
32 
33 }  // namespace
34 
CPDF_SampledFunc()35 CPDF_SampledFunc::CPDF_SampledFunc() : CPDF_Function(Type::kType0Sampled) {}
36 
~CPDF_SampledFunc()37 CPDF_SampledFunc::~CPDF_SampledFunc() {}
38 
v_Init(CPDF_Object * pObj)39 bool CPDF_SampledFunc::v_Init(CPDF_Object* pObj) {
40   CPDF_Stream* pStream = pObj->AsStream();
41   if (!pStream)
42     return false;
43 
44   CPDF_Dictionary* pDict = pStream->GetDict();
45   CPDF_Array* pSize = pDict->GetArrayFor("Size");
46   CPDF_Array* pEncode = pDict->GetArrayFor("Encode");
47   CPDF_Array* pDecode = pDict->GetArrayFor("Decode");
48   m_nBitsPerSample = pDict->GetIntegerFor("BitsPerSample");
49   if (!IsValidBitsPerSample(m_nBitsPerSample))
50     return false;
51 
52   m_SampleMax = 0xffffffff >> (32 - m_nBitsPerSample);
53   m_pSampleStream = pdfium::MakeRetain<CPDF_StreamAcc>(pStream);
54   m_pSampleStream->LoadAllDataFiltered();
55   FX_SAFE_UINT32 nTotalSampleBits = 1;
56   m_EncodeInfo.resize(m_nInputs);
57   for (uint32_t i = 0; i < m_nInputs; i++) {
58     m_EncodeInfo[i].sizes = pSize ? pSize->GetIntegerAt(i) : 0;
59     if (!pSize && i == 0)
60       m_EncodeInfo[i].sizes = pDict->GetIntegerFor("Size");
61     nTotalSampleBits *= m_EncodeInfo[i].sizes;
62     if (pEncode) {
63       m_EncodeInfo[i].encode_min = pEncode->GetFloatAt(i * 2);
64       m_EncodeInfo[i].encode_max = pEncode->GetFloatAt(i * 2 + 1);
65     } else {
66       m_EncodeInfo[i].encode_min = 0;
67       m_EncodeInfo[i].encode_max =
68           m_EncodeInfo[i].sizes == 1 ? 1 : (float)m_EncodeInfo[i].sizes - 1;
69     }
70   }
71   nTotalSampleBits *= m_nBitsPerSample;
72   nTotalSampleBits *= m_nOutputs;
73   FX_SAFE_UINT32 nTotalSampleBytes = nTotalSampleBits;
74   nTotalSampleBytes += 7;
75   nTotalSampleBytes /= 8;
76   if (!nTotalSampleBytes.IsValid() || nTotalSampleBytes.ValueOrDie() == 0 ||
77       nTotalSampleBytes.ValueOrDie() > m_pSampleStream->GetSize()) {
78     return false;
79   }
80   m_DecodeInfo.resize(m_nOutputs);
81   for (uint32_t i = 0; i < m_nOutputs; i++) {
82     if (pDecode) {
83       m_DecodeInfo[i].decode_min = pDecode->GetFloatAt(2 * i);
84       m_DecodeInfo[i].decode_max = pDecode->GetFloatAt(2 * i + 1);
85     } else {
86       m_DecodeInfo[i].decode_min = m_pRanges[i * 2];
87       m_DecodeInfo[i].decode_max = m_pRanges[i * 2 + 1];
88     }
89   }
90   return true;
91 }
92 
v_Call(float * inputs,float * results) const93 bool CPDF_SampledFunc::v_Call(float* inputs, float* results) const {
94   int pos = 0;
95   CFX_FixedBufGrow<float, 16> encoded_input_buf(m_nInputs);
96   float* encoded_input = encoded_input_buf;
97   CFX_FixedBufGrow<uint32_t, 32> int_buf(m_nInputs * 2);
98   uint32_t* index = int_buf;
99   uint32_t* blocksize = index + m_nInputs;
100   for (uint32_t i = 0; i < m_nInputs; i++) {
101     if (i == 0)
102       blocksize[i] = 1;
103     else
104       blocksize[i] = blocksize[i - 1] * m_EncodeInfo[i - 1].sizes;
105     encoded_input[i] =
106         Interpolate(inputs[i], m_pDomains[i * 2], m_pDomains[i * 2 + 1],
107                     m_EncodeInfo[i].encode_min, m_EncodeInfo[i].encode_max);
108     index[i] = pdfium::clamp(static_cast<uint32_t>(encoded_input[i]), 0U,
109                              m_EncodeInfo[i].sizes - 1);
110     pos += index[i] * blocksize[i];
111   }
112   FX_SAFE_INT32 bits_to_output = m_nOutputs;
113   bits_to_output *= m_nBitsPerSample;
114   if (!bits_to_output.IsValid())
115     return false;
116 
117   FX_SAFE_INT32 bitpos = pos;
118   bitpos *= bits_to_output.ValueOrDie();
119   if (!bitpos.IsValid())
120     return false;
121 
122   FX_SAFE_INT32 range_check = bitpos;
123   range_check += bits_to_output.ValueOrDie();
124   if (!range_check.IsValid())
125     return false;
126 
127   const uint8_t* pSampleData = m_pSampleStream->GetData();
128   if (!pSampleData)
129     return false;
130 
131   for (uint32_t j = 0; j < m_nOutputs; j++, bitpos += m_nBitsPerSample) {
132     uint32_t sample =
133         GetBits32(pSampleData, bitpos.ValueOrDie(), m_nBitsPerSample);
134     float encoded = (float)sample;
135     for (uint32_t i = 0; i < m_nInputs; i++) {
136       if (index[i] == m_EncodeInfo[i].sizes - 1) {
137         if (index[i] == 0)
138           encoded = encoded_input[i] * (float)sample;
139       } else {
140         FX_SAFE_INT32 bitpos2 = blocksize[i];
141         bitpos2 += pos;
142         bitpos2 *= m_nOutputs;
143         bitpos2 += j;
144         bitpos2 *= m_nBitsPerSample;
145         if (!bitpos2.IsValid())
146           return false;
147         uint32_t sample1 =
148             GetBits32(pSampleData, bitpos2.ValueOrDie(), m_nBitsPerSample);
149         encoded +=
150             (encoded_input[i] - index[i]) * ((float)sample1 - (float)sample);
151       }
152     }
153     results[j] =
154         Interpolate(encoded, 0, (float)m_SampleMax, m_DecodeInfo[j].decode_min,
155                     m_DecodeInfo[j].decode_max);
156   }
157   return true;
158 }
159