• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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