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