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