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