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