xref: /aosp_15_r20/external/pdfium/core/fxcodec/gif/cfx_gifcontext_unittest.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 #include "core/fxcodec/gif/cfx_gifcontext.h"
6 
7 #include <stdint.h>
8 
9 #include <utility>
10 
11 #include "core/fxcodec/cfx_codec_memory.h"
12 #include "core/fxcrt/data_vector.h"
13 #include "core/fxcrt/span_util.h"
14 #include "testing/gtest/include/gtest/gtest.h"
15 
16 namespace fxcodec {
17 
18 class CFX_GifContextForTest final : public CFX_GifContext {
19  public:
CFX_GifContextForTest()20   CFX_GifContextForTest() : CFX_GifContext(nullptr) {}
21   ~CFX_GifContextForTest() override = default;
22 
23   using CFX_GifContext::ReadAllOrNone;
24   using CFX_GifContext::ReadGifSignature;
25   using CFX_GifContext::ReadLogicalScreenDescriptor;
26 
InputBuffer() const27   CFX_CodecMemory* InputBuffer() const { return input_buffer_.Get(); }
SetTestInputBuffer(pdfium::span<uint8_t> input)28   void SetTestInputBuffer(pdfium::span<uint8_t> input) {
29     auto pMemory = pdfium::MakeRetain<CFX_CodecMemory>(input.size());
30     fxcrt::spancpy(pMemory->GetBufferSpan(), input);
31     SetInputBuffer(std::move(pMemory));
32   }
33 };
34 
TEST(CFX_GifContext,SetInputBuffer)35 TEST(CFX_GifContext, SetInputBuffer) {
36   uint8_t buffer[] = {0x00, 0x01, 0x02};
37   CFX_GifContextForTest context;
38 
39   context.SetTestInputBuffer({nullptr, 0});
40   EXPECT_EQ(0u, context.InputBuffer()->GetSize());
41   EXPECT_EQ(0u, context.InputBuffer()->GetPosition());
42 
43   context.SetTestInputBuffer({buffer, 0});
44   EXPECT_EQ(0u, context.InputBuffer()->GetSize());
45   EXPECT_EQ(0u, context.InputBuffer()->GetPosition());
46 
47   context.SetTestInputBuffer({buffer, 3});
48   EXPECT_EQ(3u, context.InputBuffer()->GetSize());
49   EXPECT_EQ(0u, context.InputBuffer()->GetPosition());
50 }
51 
TEST(CFX_GifContext,ReadAllOrNone)52 TEST(CFX_GifContext, ReadAllOrNone) {
53   DataVector<uint8_t> dest_buffer;
54   uint8_t src_buffer[] = {0x00, 0x01, 0x02, 0x03, 0x04,
55                           0x05, 0x06, 0x07, 0x08, 0x09};
56   CFX_GifContextForTest context;
57 
58   context.SetTestInputBuffer({nullptr, 0});
59   EXPECT_FALSE(context.ReadAllOrNone(nullptr, 0));
60   EXPECT_FALSE(context.ReadAllOrNone(nullptr, 10));
61 
62   EXPECT_FALSE(context.ReadAllOrNone(dest_buffer.data(), 0));
63   EXPECT_FALSE(context.ReadAllOrNone(dest_buffer.data(), 10));
64 
65   context.SetTestInputBuffer({src_buffer, 0});
66   dest_buffer.resize(sizeof(src_buffer));
67   EXPECT_FALSE(context.ReadAllOrNone(dest_buffer.data(), sizeof(src_buffer)));
68 
69   context.SetTestInputBuffer({src_buffer, 1});
70   EXPECT_FALSE(context.ReadAllOrNone(dest_buffer.data(), sizeof(src_buffer)));
71   EXPECT_EQ(0u, context.InputBuffer()->GetPosition());
72   EXPECT_FALSE(context.ReadAllOrNone(nullptr, sizeof(src_buffer)));
73   EXPECT_FALSE(context.ReadAllOrNone(nullptr, 1));
74   EXPECT_TRUE(context.ReadAllOrNone(dest_buffer.data(), 1));
75   EXPECT_EQ(src_buffer[0], dest_buffer[0]);
76 
77   context.SetTestInputBuffer(src_buffer);
78   EXPECT_FALSE(context.ReadAllOrNone(nullptr, sizeof(src_buffer)));
79   EXPECT_TRUE(context.ReadAllOrNone(dest_buffer.data(), sizeof(src_buffer)));
80   for (size_t i = 0; i < sizeof(src_buffer); i++)
81     EXPECT_EQ(src_buffer[i], dest_buffer[i]);
82 
83   context.SetTestInputBuffer(src_buffer);
84   for (size_t i = 0; i < sizeof(src_buffer); i++) {
85     EXPECT_TRUE(context.ReadAllOrNone(dest_buffer.data(), 1));
86     EXPECT_EQ(src_buffer[i], dest_buffer[0]);
87   }
88 }
89 
TEST(CFX_GifContext,ReadGifSignature)90 TEST(CFX_GifContext, ReadGifSignature) {
91   CFX_GifContextForTest context;
92   {
93     uint8_t data[1];
94     context.SetTestInputBuffer({data, 0});
95     EXPECT_EQ(GifDecoder::Status::kUnfinished, context.ReadGifSignature());
96     EXPECT_EQ(0u, context.InputBuffer()->GetPosition());
97     context.SetTestInputBuffer({});
98   }
99   // Make sure testing the entire signature
100   {
101     uint8_t data[] = {'G', 'I', 'F'};
102     context.SetTestInputBuffer(data);
103     EXPECT_EQ(GifDecoder::Status::kUnfinished, context.ReadGifSignature());
104     EXPECT_EQ(0u, context.InputBuffer()->GetPosition());
105     context.SetTestInputBuffer({});
106   }
107   {
108     uint8_t data[] = {'N', 'O', 'T', 'G', 'I', 'F'};
109     context.SetTestInputBuffer(data);
110     EXPECT_EQ(GifDecoder::Status::kError, context.ReadGifSignature());
111     EXPECT_EQ(6u, context.InputBuffer()->GetPosition());
112     context.SetTestInputBuffer({});
113   }
114   // Make sure not matching GIF8*a
115   {
116     uint8_t data[] = {'G', 'I', 'F', '8', '0', 'a'};
117     context.SetTestInputBuffer(data);
118     EXPECT_EQ(GifDecoder::Status::kError, context.ReadGifSignature());
119     EXPECT_EQ(6u, context.InputBuffer()->GetPosition());
120     context.SetTestInputBuffer({});
121   }
122   // Make sure not matching GIF**a
123   {
124     uint8_t data[] = {'G', 'I', 'F', '9', '2', 'a'};
125     context.SetTestInputBuffer(data);
126     EXPECT_EQ(GifDecoder::Status::kError, context.ReadGifSignature());
127     EXPECT_EQ(6u, context.InputBuffer()->GetPosition());
128     context.SetTestInputBuffer({});
129   }
130   // One valid signature
131   {
132     uint8_t data[] = {'G', 'I', 'F', '8', '7', 'a'};
133     context.SetTestInputBuffer(data);
134     EXPECT_EQ(GifDecoder::Status::kSuccess, context.ReadGifSignature());
135     EXPECT_EQ(6u, context.InputBuffer()->GetPosition());
136     context.SetTestInputBuffer({});
137   }
138   // The other valid signature
139   {
140     uint8_t data[] = {'G', 'I', 'F', '8', '9', 'a'};
141     context.SetTestInputBuffer(data);
142     EXPECT_EQ(GifDecoder::Status::kSuccess, context.ReadGifSignature());
143     EXPECT_EQ(6u, context.InputBuffer()->GetPosition());
144     context.SetTestInputBuffer({});
145   }
146 }
147 
TEST(CFX_GifContext,ReadLocalScreenDescriptor)148 TEST(CFX_GifContext, ReadLocalScreenDescriptor) {
149   CFX_GifContextForTest context;
150   {
151     uint8_t data[1];
152     context.SetTestInputBuffer({data, 0});
153     EXPECT_EQ(GifDecoder::Status::kUnfinished,
154               context.ReadLogicalScreenDescriptor());
155     context.SetTestInputBuffer({});
156   }
157   // LSD with all the values zero'd
158   {
159     uint8_t lsd[sizeof(CFX_GifLocalScreenDescriptor)];
160     memset(&lsd, 0, sizeof(CFX_GifLocalScreenDescriptor));
161     context.SetTestInputBuffer(lsd);
162 
163     EXPECT_EQ(GifDecoder::Status::kSuccess,
164               context.ReadLogicalScreenDescriptor());
165 
166     EXPECT_EQ(sizeof(CFX_GifLocalScreenDescriptor),
167               static_cast<size_t>(context.InputBuffer()->GetPosition()));
168     EXPECT_EQ(0, context.width_);
169     EXPECT_EQ(0, context.height_);
170     EXPECT_EQ(0u, context.bc_index_);
171     context.SetTestInputBuffer({});
172   }
173   // LSD with no global palette
174   {
175     uint8_t lsd[sizeof(CFX_GifLocalScreenDescriptor)] = {0x0A, 0x00, 0x00, 0x0F,
176                                                          0x00, 0x01, 0x02};
177     context.SetTestInputBuffer(lsd);
178 
179     EXPECT_EQ(GifDecoder::Status::kSuccess,
180               context.ReadLogicalScreenDescriptor());
181 
182     EXPECT_EQ(sizeof(CFX_GifLocalScreenDescriptor),
183               static_cast<size_t>(context.InputBuffer()->GetPosition()));
184     EXPECT_EQ(0x000A, context.width_);
185     EXPECT_EQ(0x0F00, context.height_);
186     EXPECT_EQ(0u, context.bc_index_);  // bc_index_ is 0 if no global palette
187     context.SetTestInputBuffer({});
188   }
189   // LSD with global palette bit set, but no global palette
190   {
191     uint8_t lsd[sizeof(CFX_GifLocalScreenDescriptor)] = {0x0A, 0x00, 0x00, 0x0F,
192                                                          0x80, 0x01, 0x02};
193     context.SetTestInputBuffer(lsd);
194 
195     EXPECT_EQ(GifDecoder::Status::kUnfinished,
196               context.ReadLogicalScreenDescriptor());
197 
198     EXPECT_EQ(0u, context.InputBuffer()->GetPosition());
199     context.SetTestInputBuffer({});
200   }
201   // LSD with global palette
202   {
203     struct {
204       uint8_t lsd[sizeof(CFX_GifLocalScreenDescriptor)];
205       uint8_t palette[4 * sizeof(CFX_GifPalette)];
206     } data = {{0x0A, 0x00, 0x00, 0x0F, 0xA9, 0x01, 0x02},
207               {0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1}};
208     context.SetTestInputBuffer(
209         {reinterpret_cast<uint8_t*>(&data), sizeof(data)});
210 
211     EXPECT_EQ(GifDecoder::Status::kSuccess,
212               context.ReadLogicalScreenDescriptor());
213 
214     EXPECT_EQ(sizeof(data), context.InputBuffer()->GetPosition());
215     EXPECT_EQ(0x000A, context.width_);
216     EXPECT_EQ(0x0F00, context.height_);
217     EXPECT_EQ(1u, context.bc_index_);
218     EXPECT_EQ(1u, context.global_palette_exp_);
219     EXPECT_EQ(1, context.global_sort_flag_);
220     EXPECT_EQ(2, context.global_color_resolution_);
221     EXPECT_EQ(0, memcmp(data.palette, context.global_palette_.data(),
222                         sizeof(data.palette)));
223     context.SetTestInputBuffer({});
224   }
225 }
226 
TEST(CFX_GifContext,ReadHeader)227 TEST(CFX_GifContext, ReadHeader) {
228   CFX_GifContextForTest context;
229   // Bad signature
230   {
231     struct {
232       uint8_t signature[6];
233       uint8_t lsd[sizeof(CFX_GifLocalScreenDescriptor)];
234     } data = {{'N', 'O', 'T', 'G', 'I', 'F'},
235               {0x0A, 0x00, 0x00, 0x0F, 0x00, 0x01, 0x02}};
236     context.SetTestInputBuffer(
237         {reinterpret_cast<uint8_t*>(&data), sizeof(data)});
238 
239     EXPECT_EQ(GifDecoder::Status::kError, context.ReadHeader());
240     EXPECT_EQ(sizeof(data.signature), context.InputBuffer()->GetPosition());
241     context.SetTestInputBuffer({});
242   }
243   // Short after signature
244   {
245     uint8_t signature[] = {'G', 'I', 'F', '8', '7', 'a'};
246     context.SetTestInputBuffer(
247         {reinterpret_cast<uint8_t*>(&signature), sizeof(signature)});
248 
249     EXPECT_EQ(GifDecoder::Status::kUnfinished, context.ReadHeader());
250     EXPECT_EQ(sizeof(signature), context.InputBuffer()->GetPosition());
251     context.SetTestInputBuffer({});
252   }
253   // Success without global palette
254   {
255     struct {
256       uint8_t signature[6];
257       uint8_t lsd[sizeof(CFX_GifLocalScreenDescriptor)];
258     } data = {{'G', 'I', 'F', '8', '7', 'a'},
259               {0x0A, 0x00, 0x00, 0x0F, 0x00, 0x01, 0x02}};
260     context.SetTestInputBuffer(
261         {reinterpret_cast<uint8_t*>(&data), sizeof(data)});
262 
263     EXPECT_EQ(GifDecoder::Status::kSuccess, context.ReadHeader());
264     EXPECT_EQ(sizeof(data), context.InputBuffer()->GetPosition());
265     EXPECT_EQ(0x000A, context.width_);
266     EXPECT_EQ(0x0F00, context.height_);
267     EXPECT_EQ(0u, context.bc_index_);  // bc_index_ is 0 if no global palette
268     context.SetTestInputBuffer({});
269   }
270   // Missing Global Palette
271   {
272     struct {
273       uint8_t signature[6];
274       uint8_t lsd[sizeof(CFX_GifLocalScreenDescriptor)];
275     } data = {{'G', 'I', 'F', '8', '7', 'a'},
276               {0x0A, 0x00, 0x00, 0x0F, 0x80, 0x01, 0x02}};
277     context.SetTestInputBuffer(
278         {reinterpret_cast<uint8_t*>(&data), sizeof(data)});
279 
280     EXPECT_EQ(GifDecoder::Status::kUnfinished, context.ReadHeader());
281     EXPECT_EQ(sizeof(data.signature), context.InputBuffer()->GetPosition());
282     context.SetTestInputBuffer({});
283   }
284   // Success with global palette
285   {
286     struct {
287       uint8_t signature[6];
288       uint8_t lsd[sizeof(CFX_GifLocalScreenDescriptor)];
289       uint8_t palette[4 * sizeof(CFX_GifPalette)];
290     } data = {{'G', 'I', 'F', '8', '7', 'a'},
291               {0x0A, 0x00, 0x00, 0x0F, 0xA9, 0x01, 0x02},
292               {0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1}};
293     context.SetTestInputBuffer(
294         {reinterpret_cast<uint8_t*>(&data), sizeof(data)});
295 
296     EXPECT_EQ(GifDecoder::Status::kSuccess, context.ReadHeader());
297     EXPECT_EQ(sizeof(data), context.InputBuffer()->GetPosition());
298     EXPECT_EQ(0x000A, context.width_);
299     EXPECT_EQ(0x0F00, context.height_);
300     EXPECT_EQ(1u, context.bc_index_);
301     EXPECT_EQ(1u, context.global_palette_exp_);
302     EXPECT_EQ(1, context.global_sort_flag_);
303     EXPECT_EQ(2, context.global_color_resolution_);
304     EXPECT_EQ(0, memcmp(data.palette, context.global_palette_.data(),
305                         sizeof(data.palette)));
306     context.SetTestInputBuffer({});
307   }
308 }
309 
310 }  // namespace fxcodec
311