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