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/fpdfapi/parser/cpdf_dictionary.h"
11 #include "core/fpdfapi/parser/cpdf_stream.h"
12 #include "core/fpdfapi/parser/cpdf_stream_acc.h"
13 #include "core/fxcrt/cfx_bitstream.h"
14 #include "core/fxcrt/cfx_fixedbufgrow.h"
15 #include "core/fxcrt/fx_safe_types.h"
16 #include "third_party/base/stl_util.h"
17
18 namespace {
19
20 // See PDF Reference 1.7, page 170, table 3.36.
IsValidBitsPerSample(uint32_t x)21 bool IsValidBitsPerSample(uint32_t x) {
22 switch (x) {
23 case 1:
24 case 2:
25 case 4:
26 case 8:
27 case 12:
28 case 16:
29 case 24:
30 case 32:
31 return true;
32 default:
33 return false;
34 }
35 }
36
37 } // namespace
38
CPDF_SampledFunc()39 CPDF_SampledFunc::CPDF_SampledFunc() : CPDF_Function(Type::kType0Sampled) {}
40
~CPDF_SampledFunc()41 CPDF_SampledFunc::~CPDF_SampledFunc() {}
42
v_Init(const CPDF_Object * pObj,std::set<const CPDF_Object * > * pVisited)43 bool CPDF_SampledFunc::v_Init(const CPDF_Object* pObj,
44 std::set<const CPDF_Object*>* pVisited) {
45 const CPDF_Stream* pStream = pObj->AsStream();
46 if (!pStream)
47 return false;
48
49 const CPDF_Dictionary* pDict = pStream->GetDict();
50 const CPDF_Array* pSize = pDict->GetArrayFor("Size");
51 if (!pSize || pSize->IsEmpty())
52 return false;
53
54 m_nBitsPerSample = pDict->GetIntegerFor("BitsPerSample");
55 if (!IsValidBitsPerSample(m_nBitsPerSample))
56 return false;
57
58 FX_SAFE_UINT32 nTotalSampleBits = m_nBitsPerSample;
59 nTotalSampleBits *= m_nOutputs;
60 const CPDF_Array* pEncode = pDict->GetArrayFor("Encode");
61 m_EncodeInfo.resize(m_nInputs);
62 for (uint32_t i = 0; i < m_nInputs; i++) {
63 int size = pSize->GetIntegerAt(i);
64 if (size <= 0)
65 return false;
66
67 m_EncodeInfo[i].sizes = size;
68 nTotalSampleBits *= m_EncodeInfo[i].sizes;
69 if (pEncode) {
70 m_EncodeInfo[i].encode_min = pEncode->GetNumberAt(i * 2);
71 m_EncodeInfo[i].encode_max = pEncode->GetNumberAt(i * 2 + 1);
72 } else {
73 m_EncodeInfo[i].encode_min = 0;
74 m_EncodeInfo[i].encode_max =
75 m_EncodeInfo[i].sizes == 1 ? 1 : m_EncodeInfo[i].sizes - 1;
76 }
77 }
78 FX_SAFE_UINT32 nTotalSampleBytes = (nTotalSampleBits + 7) / 8;
79 if (!nTotalSampleBytes.IsValid() || nTotalSampleBytes.ValueOrDie() == 0)
80 return false;
81
82 m_SampleMax = 0xffffffff >> (32 - m_nBitsPerSample);
83 m_pSampleStream = pdfium::MakeRetain<CPDF_StreamAcc>(pStream);
84 m_pSampleStream->LoadAllDataFiltered();
85 if (nTotalSampleBytes.ValueOrDie() > m_pSampleStream->GetSize())
86 return false;
87
88 const CPDF_Array* pDecode = pDict->GetArrayFor("Decode");
89 m_DecodeInfo.resize(m_nOutputs);
90 for (uint32_t i = 0; i < m_nOutputs; i++) {
91 if (pDecode) {
92 m_DecodeInfo[i].decode_min = pDecode->GetNumberAt(2 * i);
93 m_DecodeInfo[i].decode_max = pDecode->GetNumberAt(2 * i + 1);
94 } else {
95 m_DecodeInfo[i].decode_min = m_Ranges[i * 2];
96 m_DecodeInfo[i].decode_max = m_Ranges[i * 2 + 1];
97 }
98 }
99 return true;
100 }
101
v_Call(const float * inputs,float * results) const102 bool CPDF_SampledFunc::v_Call(const float* inputs, float* results) const {
103 int pos = 0;
104 CFX_FixedBufGrow<float, 16> encoded_input_buf(m_nInputs);
105 float* encoded_input = encoded_input_buf;
106 CFX_FixedBufGrow<uint32_t, 32> int_buf(m_nInputs * 2);
107 uint32_t* index = int_buf;
108 uint32_t* blocksize = index + m_nInputs;
109 for (uint32_t i = 0; i < m_nInputs; i++) {
110 if (i == 0)
111 blocksize[i] = 1;
112 else
113 blocksize[i] = blocksize[i - 1] * m_EncodeInfo[i - 1].sizes;
114 encoded_input[i] =
115 Interpolate(inputs[i], m_Domains[i * 2], m_Domains[i * 2 + 1],
116 m_EncodeInfo[i].encode_min, m_EncodeInfo[i].encode_max);
117 index[i] = pdfium::clamp(static_cast<uint32_t>(encoded_input[i]), 0U,
118 m_EncodeInfo[i].sizes - 1);
119 pos += index[i] * blocksize[i];
120 }
121 FX_SAFE_INT32 bits_to_output = m_nOutputs;
122 bits_to_output *= m_nBitsPerSample;
123 if (!bits_to_output.IsValid())
124 return false;
125
126 int bits_to_skip;
127 {
128 FX_SAFE_INT32 bitpos = pos;
129 bitpos *= bits_to_output.ValueOrDie();
130 bits_to_skip = bitpos.ValueOrDefault(-1);
131 if (bits_to_skip < 0)
132 return false;
133
134 FX_SAFE_INT32 range_check = bitpos;
135 range_check += bits_to_output.ValueOrDie();
136 if (!range_check.IsValid())
137 return false;
138 }
139
140 pdfium::span<const uint8_t> pSampleData = m_pSampleStream->GetSpan();
141 if (pSampleData.empty())
142 return false;
143
144 CFX_BitStream bitstream(pSampleData);
145 bitstream.SkipBits(bits_to_skip);
146 for (uint32_t i = 0; i < m_nOutputs; ++i) {
147 uint32_t sample = bitstream.GetBits(m_nBitsPerSample);
148 float encoded = sample;
149 for (uint32_t j = 0; j < m_nInputs; ++j) {
150 if (index[j] == m_EncodeInfo[j].sizes - 1) {
151 if (index[j] == 0)
152 encoded = encoded_input[j] * sample;
153 } else {
154 FX_SAFE_INT32 bitpos2 = blocksize[j];
155 bitpos2 += pos;
156 bitpos2 *= m_nOutputs;
157 bitpos2 += i;
158 bitpos2 *= m_nBitsPerSample;
159 int bits_to_skip2 = bitpos2.ValueOrDefault(-1);
160 if (bits_to_skip2 < 0)
161 return false;
162
163 CFX_BitStream bitstream2(pSampleData);
164 bitstream2.SkipBits(bits_to_skip2);
165 float sample2 =
166 static_cast<float>(bitstream2.GetBits(m_nBitsPerSample));
167 encoded += (encoded_input[j] - index[j]) * (sample2 - sample);
168 }
169 }
170 results[i] =
171 Interpolate(encoded, 0, m_SampleMax, m_DecodeInfo[i].decode_min,
172 m_DecodeInfo[i].decode_max);
173 }
174 return true;
175 }
176
177 #if defined _SKIA_SUPPORT_ || defined _SKIA_SUPPORT_PATHS_
GetSampleStream() const178 RetainPtr<CPDF_StreamAcc> CPDF_SampledFunc::GetSampleStream() const {
179 return m_pSampleStream;
180 }
181 #endif
182