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 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6
7 #include "core/fxcodec/gif/cfx_gifcontext.h"
8
9 #include <stdint.h>
10
11 #include <algorithm>
12 #include <iterator>
13 #include <utility>
14
15 #include "core/fxcodec/cfx_codec_memory.h"
16 #include "core/fxcrt/data_vector.h"
17 #include "core/fxcrt/fx_system.h"
18 #include "core/fxcrt/stl_util.h"
19
20 namespace fxcodec {
21
22 namespace {
23
24 constexpr int32_t kGifInterlaceStep[4] = {8, 8, 4, 2};
25
26 } // namespace
27
CFX_GifContext(GifDecoder::Delegate * delegate)28 CFX_GifContext::CFX_GifContext(GifDecoder::Delegate* delegate)
29 : delegate_(delegate) {}
30
31 CFX_GifContext::~CFX_GifContext() = default;
32
ReadScanline(int32_t row_num,pdfium::span<uint8_t> row_buf)33 void CFX_GifContext::ReadScanline(int32_t row_num,
34 pdfium::span<uint8_t> row_buf) {
35 delegate_->GifReadScanline(row_num, row_buf);
36 }
37
GetRecordPosition(uint32_t cur_pos,int32_t left,int32_t top,int32_t width,int32_t height,int32_t pal_num,CFX_GifPalette * pal,int32_t trans_index,bool interlace)38 bool CFX_GifContext::GetRecordPosition(uint32_t cur_pos,
39 int32_t left,
40 int32_t top,
41 int32_t width,
42 int32_t height,
43 int32_t pal_num,
44 CFX_GifPalette* pal,
45 int32_t trans_index,
46 bool interlace) {
47 return delegate_->GifInputRecordPositionBuf(
48 cur_pos, FX_RECT(left, top, left + width, top + height), pal_num, pal,
49 trans_index, interlace);
50 }
51
ReadHeader()52 GifDecoder::Status CFX_GifContext::ReadHeader() {
53 GifDecoder::Status status = ReadGifSignature();
54 if (status != GifDecoder::Status::kSuccess)
55 return status;
56 return ReadLogicalScreenDescriptor();
57 }
58
GetFrame()59 GifDecoder::Status CFX_GifContext::GetFrame() {
60 GifDecoder::Status ret = GifDecoder::Status::kSuccess;
61 while (true) {
62 switch (decode_status_) {
63 case GIF_D_STATUS_TAIL:
64 return GifDecoder::Status::kSuccess;
65 case GIF_D_STATUS_SIG: {
66 uint8_t signature;
67 if (!ReadAllOrNone(&signature, sizeof(signature)))
68 return GifDecoder::Status::kUnfinished;
69
70 switch (signature) {
71 case GIF_SIG_EXTENSION:
72 SaveDecodingStatus(GIF_D_STATUS_EXT);
73 continue;
74 case GIF_SIG_IMAGE:
75 SaveDecodingStatus(GIF_D_STATUS_IMG_INFO);
76 continue;
77 case GIF_SIG_TRAILER:
78 SaveDecodingStatus(GIF_D_STATUS_TAIL);
79 return GifDecoder::Status::kSuccess;
80 default:
81 if (!input_buffer_->IsEOF()) {
82 // The Gif File has non_standard Tag!
83 SaveDecodingStatus(GIF_D_STATUS_SIG);
84 continue;
85 }
86 // The Gif File Doesn't have Trailer Tag!
87 return GifDecoder::Status::kSuccess;
88 }
89 }
90 case GIF_D_STATUS_EXT: {
91 uint8_t extension;
92 if (!ReadAllOrNone(&extension, sizeof(extension)))
93 return GifDecoder::Status::kUnfinished;
94
95 switch (extension) {
96 case GIF_BLOCK_CE:
97 SaveDecodingStatus(GIF_D_STATUS_EXT_CE);
98 continue;
99 case GIF_BLOCK_GCE:
100 SaveDecodingStatus(GIF_D_STATUS_EXT_GCE);
101 continue;
102 case GIF_BLOCK_PTE:
103 SaveDecodingStatus(GIF_D_STATUS_EXT_PTE);
104 continue;
105 default: {
106 int32_t status = GIF_D_STATUS_EXT_UNE;
107 if (extension == GIF_BLOCK_PTE) {
108 status = GIF_D_STATUS_EXT_PTE;
109 }
110 SaveDecodingStatus(status);
111 continue;
112 }
113 }
114 }
115 case GIF_D_STATUS_IMG_INFO: {
116 ret = DecodeImageInfo();
117 if (ret != GifDecoder::Status::kSuccess)
118 return ret;
119
120 continue;
121 }
122 case GIF_D_STATUS_IMG_DATA: {
123 uint8_t img_data_size;
124 size_t read_marker = input_buffer_->GetPosition();
125
126 if (!ReadAllOrNone(&img_data_size, sizeof(img_data_size)))
127 return GifDecoder::Status::kUnfinished;
128
129 while (img_data_size != GIF_BLOCK_TERMINAL) {
130 if (!input_buffer_->Seek(input_buffer_->GetPosition() +
131 img_data_size)) {
132 input_buffer_->Seek(read_marker);
133 return GifDecoder::Status::kUnfinished;
134 }
135
136 // This saving of the scan state on partial reads is why
137 // ScanForTerminalMarker() cannot be used here.
138 SaveDecodingStatus(GIF_D_STATUS_IMG_DATA);
139 read_marker = input_buffer_->GetPosition();
140 if (!ReadAllOrNone(&img_data_size, sizeof(img_data_size)))
141 return GifDecoder::Status::kUnfinished;
142 }
143
144 SaveDecodingStatus(GIF_D_STATUS_SIG);
145 continue;
146 }
147 default: {
148 ret = DecodeExtension();
149 if (ret != GifDecoder::Status::kSuccess)
150 return ret;
151 break;
152 }
153 }
154 }
155 }
156
LoadFrame(size_t frame_num)157 GifDecoder::Status CFX_GifContext::LoadFrame(size_t frame_num) {
158 if (frame_num >= images_.size())
159 return GifDecoder::Status::kError;
160
161 CFX_GifImage* gif_image = images_[frame_num].get();
162 if (gif_image->image_info.height == 0)
163 return GifDecoder::Status::kError;
164
165 uint32_t gif_img_row_bytes = gif_image->image_info.width;
166 if (gif_img_row_bytes == 0)
167 return GifDecoder::Status::kError;
168
169 if (decode_status_ == GIF_D_STATUS_TAIL) {
170 gif_image->row_buffer.resize(gif_img_row_bytes);
171 CFX_GifGraphicControlExtension* gif_img_gce = gif_image->image_GCE.get();
172 int32_t loc_pal_num =
173 gif_image->image_info.local_flags.local_pal
174 ? (2 << gif_image->image_info.local_flags.pal_bits)
175 : 0;
176 CFX_GifPalette* pLocalPalette = gif_image->local_palettes.empty()
177 ? nullptr
178 : gif_image->local_palettes.data();
179 if (!gif_img_gce) {
180 bool bRes = GetRecordPosition(
181 gif_image->data_pos, gif_image->image_info.left,
182 gif_image->image_info.top, gif_image->image_info.width,
183 gif_image->image_info.height, loc_pal_num, pLocalPalette, -1,
184 gif_image->image_info.local_flags.interlace);
185 if (!bRes) {
186 gif_image->row_buffer.clear();
187 return GifDecoder::Status::kError;
188 }
189 } else {
190 bool bRes = GetRecordPosition(
191 gif_image->data_pos, gif_image->image_info.left,
192 gif_image->image_info.top, gif_image->image_info.width,
193 gif_image->image_info.height, loc_pal_num, pLocalPalette,
194 gif_image->image_GCE->gce_flags.transparency
195 ? static_cast<int32_t>(gif_image->image_GCE->trans_index)
196 : -1,
197 gif_image->image_info.local_flags.interlace);
198 if (!bRes) {
199 gif_image->row_buffer.clear();
200 return GifDecoder::Status::kError;
201 }
202 }
203
204 if (gif_image->code_exp > GIF_MAX_LZW_EXP) {
205 gif_image->row_buffer.clear();
206 return GifDecoder::Status::kError;
207 }
208
209 img_row_offset_ = 0;
210 img_row_avail_size_ = 0;
211 img_pass_num_ = 0;
212 gif_image->row_num = 0;
213 SaveDecodingStatus(GIF_D_STATUS_IMG_DATA);
214 }
215
216 uint8_t img_data_size;
217 DataVector<uint8_t> img_data;
218 size_t read_marker = input_buffer_->GetPosition();
219
220 // TODO(crbug.com/pdfium/1793): This logic can be simplified a lot, but it
221 // probably makes more sense to switch to a different GIF decoder altogether.
222 if (decode_status_ == GIF_D_STATUS_IMG_DATA) {
223 if (!ReadAllOrNone(&img_data_size, sizeof(img_data_size)))
224 return GifDecoder::Status::kUnfinished;
225
226 if (img_data_size != GIF_BLOCK_TERMINAL) {
227 img_data.resize(img_data_size);
228 if (!ReadAllOrNone(img_data.data(), img_data_size)) {
229 input_buffer_->Seek(read_marker);
230 return GifDecoder::Status::kUnfinished;
231 }
232
233 if (!lzw_decompressor_) {
234 lzw_decompressor_ = LZWDecompressor::Create(GetPaletteExp(gif_image),
235 gif_image->code_exp);
236 if (!lzw_decompressor_) {
237 DecodingFailureAtTailCleanup(gif_image);
238 return GifDecoder::Status::kError;
239 }
240 }
241 lzw_decompressor_->SetSource(img_data.data(), img_data_size);
242
243 SaveDecodingStatus(GIF_D_STATUS_IMG_DATA);
244 img_row_offset_ += img_row_avail_size_;
245 img_row_avail_size_ = gif_img_row_bytes - img_row_offset_;
246 LZWDecompressor::Status ret = lzw_decompressor_->Decode(
247 gif_image->row_buffer.data() + img_row_offset_, &img_row_avail_size_);
248 if (ret == LZWDecompressor::Status::kError) {
249 DecodingFailureAtTailCleanup(gif_image);
250 return GifDecoder::Status::kError;
251 }
252
253 while (ret != LZWDecompressor::Status::kError) {
254 if (ret == LZWDecompressor::Status::kSuccess) {
255 ReadScanline(gif_image->row_num, gif_image->row_buffer);
256 gif_image->row_buffer.clear();
257 SaveDecodingStatus(GIF_D_STATUS_TAIL);
258 return GifDecoder::Status::kSuccess;
259 }
260
261 if (ret == LZWDecompressor::Status::kUnfinished) {
262 read_marker = input_buffer_->GetPosition();
263 if (!ReadAllOrNone(&img_data_size, sizeof(img_data_size)))
264 return GifDecoder::Status::kUnfinished;
265
266 if (img_data_size != GIF_BLOCK_TERMINAL) {
267 img_data.resize(img_data_size);
268 if (!ReadAllOrNone(img_data.data(), img_data_size)) {
269 input_buffer_->Seek(read_marker);
270 return GifDecoder::Status::kUnfinished;
271 }
272
273 lzw_decompressor_->SetSource(img_data.data(), img_data_size);
274
275 SaveDecodingStatus(GIF_D_STATUS_IMG_DATA);
276 img_row_offset_ += img_row_avail_size_;
277 img_row_avail_size_ = gif_img_row_bytes - img_row_offset_;
278 ret = lzw_decompressor_->Decode(
279 gif_image->row_buffer.data() + img_row_offset_,
280 &img_row_avail_size_);
281 }
282 }
283
284 if (ret == LZWDecompressor::Status::kInsufficientDestSize) {
285 if (gif_image->image_info.local_flags.interlace) {
286 ReadScanline(gif_image->row_num, gif_image->row_buffer);
287 gif_image->row_num += kGifInterlaceStep[img_pass_num_];
288 if (gif_image->row_num >=
289 static_cast<int32_t>(gif_image->image_info.height)) {
290 img_pass_num_++;
291 if (img_pass_num_ == std::size(kGifInterlaceStep)) {
292 DecodingFailureAtTailCleanup(gif_image);
293 return GifDecoder::Status::kError;
294 }
295 gif_image->row_num = kGifInterlaceStep[img_pass_num_] / 2;
296 }
297 } else {
298 ReadScanline(gif_image->row_num++, gif_image->row_buffer);
299 }
300
301 img_row_offset_ = 0;
302 img_row_avail_size_ = gif_img_row_bytes;
303 ret = lzw_decompressor_->Decode(
304 gif_image->row_buffer.data() + img_row_offset_,
305 &img_row_avail_size_);
306 }
307
308 if (ret == LZWDecompressor::Status::kError) {
309 DecodingFailureAtTailCleanup(gif_image);
310 return GifDecoder::Status::kError;
311 }
312 }
313 }
314 SaveDecodingStatus(GIF_D_STATUS_TAIL);
315 }
316 return GifDecoder::Status::kError;
317 }
318
SetInputBuffer(RetainPtr<CFX_CodecMemory> codec_memory)319 void CFX_GifContext::SetInputBuffer(RetainPtr<CFX_CodecMemory> codec_memory) {
320 input_buffer_ = std::move(codec_memory);
321 }
322
GetAvailInput() const323 uint32_t CFX_GifContext::GetAvailInput() const {
324 if (!input_buffer_)
325 return 0;
326
327 return pdfium::base::checked_cast<uint32_t>(input_buffer_->GetSize() -
328 input_buffer_->GetPosition());
329 }
330
ReadAllOrNone(uint8_t * dest,uint32_t size)331 bool CFX_GifContext::ReadAllOrNone(uint8_t* dest, uint32_t size) {
332 if (!input_buffer_ || !dest)
333 return false;
334
335 size_t read_marker = input_buffer_->GetPosition();
336 size_t read = input_buffer_->ReadBlock({dest, size});
337 if (read < size) {
338 input_buffer_->Seek(read_marker);
339 return false;
340 }
341
342 return true;
343 }
344
ReadGifSignature()345 GifDecoder::Status CFX_GifContext::ReadGifSignature() {
346 CFX_GifHeader header;
347 if (!ReadAllOrNone(reinterpret_cast<uint8_t*>(&header), 6))
348 return GifDecoder::Status::kUnfinished;
349
350 if (strncmp(header.signature, kGifSignature87, 6) != 0 &&
351 strncmp(header.signature, kGifSignature89, 6) != 0) {
352 return GifDecoder::Status::kError;
353 }
354
355 return GifDecoder::Status::kSuccess;
356 }
357
ReadLogicalScreenDescriptor()358 GifDecoder::Status CFX_GifContext::ReadLogicalScreenDescriptor() {
359 CFX_GifLocalScreenDescriptor lsd;
360 size_t read_marker = input_buffer_->GetPosition();
361
362 if (!ReadAllOrNone(reinterpret_cast<uint8_t*>(&lsd), sizeof(lsd)))
363 return GifDecoder::Status::kUnfinished;
364
365 if (lsd.global_flags.global_pal) {
366 uint32_t palette_count = unsigned(2 << lsd.global_flags.pal_bits);
367 if (lsd.bc_index >= palette_count)
368 return GifDecoder::Status::kError;
369 bc_index_ = lsd.bc_index;
370
371 uint32_t palette_size = palette_count * sizeof(CFX_GifPalette);
372 std::vector<CFX_GifPalette> palette(palette_count);
373 if (!ReadAllOrNone(reinterpret_cast<uint8_t*>(palette.data()),
374 palette_size)) {
375 // Roll back the read for the LSD
376 input_buffer_->Seek(read_marker);
377 return GifDecoder::Status::kUnfinished;
378 }
379
380 global_palette_exp_ = lsd.global_flags.pal_bits;
381 global_sort_flag_ = lsd.global_flags.sort_flag;
382 global_color_resolution_ = lsd.global_flags.color_resolution;
383 std::swap(global_palette_, palette);
384 }
385
386 width_ = static_cast<int>(
387 FXSYS_UINT16_GET_LSBFIRST(reinterpret_cast<uint8_t*>(&lsd.width)));
388 height_ = static_cast<int>(
389 FXSYS_UINT16_GET_LSBFIRST(reinterpret_cast<uint8_t*>(&lsd.height)));
390
391 return GifDecoder::Status::kSuccess;
392 }
393
SaveDecodingStatus(int32_t status)394 void CFX_GifContext::SaveDecodingStatus(int32_t status) {
395 decode_status_ = status;
396 }
397
DecodeExtension()398 GifDecoder::Status CFX_GifContext::DecodeExtension() {
399 size_t read_marker = input_buffer_->GetPosition();
400
401 switch (decode_status_) {
402 case GIF_D_STATUS_EXT_CE: {
403 if (!ScanForTerminalMarker()) {
404 input_buffer_->Seek(read_marker);
405 return GifDecoder::Status::kUnfinished;
406 }
407 break;
408 }
409 case GIF_D_STATUS_EXT_PTE: {
410 CFX_GifPlainTextExtension gif_pte;
411 if (!ReadAllOrNone(reinterpret_cast<uint8_t*>(&gif_pte), sizeof(gif_pte)))
412 return GifDecoder::Status::kUnfinished;
413
414 graphic_control_extension_ = nullptr;
415 if (!ScanForTerminalMarker()) {
416 input_buffer_->Seek(read_marker);
417 return GifDecoder::Status::kUnfinished;
418 }
419 break;
420 }
421 case GIF_D_STATUS_EXT_GCE: {
422 CFX_GifGraphicControlExtension gif_gce;
423 if (!ReadAllOrNone(reinterpret_cast<uint8_t*>(&gif_gce), sizeof(gif_gce)))
424 return GifDecoder::Status::kUnfinished;
425
426 if (!graphic_control_extension_.get())
427 graphic_control_extension_ =
428 std::make_unique<CFX_GifGraphicControlExtension>();
429 graphic_control_extension_->block_size = gif_gce.block_size;
430 graphic_control_extension_->gce_flags = gif_gce.gce_flags;
431 graphic_control_extension_->delay_time = FXSYS_UINT16_GET_LSBFIRST(
432 reinterpret_cast<uint8_t*>(&gif_gce.delay_time));
433 graphic_control_extension_->trans_index = gif_gce.trans_index;
434 break;
435 }
436 default: {
437 if (decode_status_ == GIF_D_STATUS_EXT_PTE)
438 graphic_control_extension_ = nullptr;
439 if (!ScanForTerminalMarker()) {
440 input_buffer_->Seek(read_marker);
441 return GifDecoder::Status::kUnfinished;
442 }
443 }
444 }
445
446 SaveDecodingStatus(GIF_D_STATUS_SIG);
447 return GifDecoder::Status::kSuccess;
448 }
449
DecodeImageInfo()450 GifDecoder::Status CFX_GifContext::DecodeImageInfo() {
451 if (width_ <= 0 || height_ <= 0)
452 return GifDecoder::Status::kError;
453
454 size_t read_marker = input_buffer_->GetPosition();
455 CFX_GifImageInfo img_info;
456 if (!ReadAllOrNone(reinterpret_cast<uint8_t*>(&img_info), sizeof(img_info)))
457 return GifDecoder::Status::kUnfinished;
458
459 auto gif_image = std::make_unique<CFX_GifImage>();
460 gif_image->image_info.left =
461 FXSYS_UINT16_GET_LSBFIRST(reinterpret_cast<uint8_t*>(&img_info.left));
462 gif_image->image_info.top =
463 FXSYS_UINT16_GET_LSBFIRST(reinterpret_cast<uint8_t*>(&img_info.top));
464 gif_image->image_info.width =
465 FXSYS_UINT16_GET_LSBFIRST(reinterpret_cast<uint8_t*>(&img_info.width));
466 gif_image->image_info.height =
467 FXSYS_UINT16_GET_LSBFIRST(reinterpret_cast<uint8_t*>(&img_info.height));
468 gif_image->image_info.local_flags = img_info.local_flags;
469 if (gif_image->image_info.left + gif_image->image_info.width > width_ ||
470 gif_image->image_info.top + gif_image->image_info.height > height_)
471 return GifDecoder::Status::kError;
472
473 CFX_GifLocalFlags* gif_img_info_lf = &img_info.local_flags;
474 if (gif_img_info_lf->local_pal) {
475 gif_image->local_palette_exp = gif_img_info_lf->pal_bits;
476 uint32_t loc_pal_count = unsigned(2 << gif_img_info_lf->pal_bits);
477 std::vector<CFX_GifPalette> loc_pal(loc_pal_count);
478 if (!ReadAllOrNone(reinterpret_cast<uint8_t*>(loc_pal.data()),
479 loc_pal_count * sizeof(CFX_GifPalette))) {
480 input_buffer_->Seek(read_marker);
481 return GifDecoder::Status::kUnfinished;
482 }
483
484 gif_image->local_palettes = std::move(loc_pal);
485 }
486
487 uint8_t code_size;
488 if (!ReadAllOrNone(&code_size, sizeof(code_size))) {
489 input_buffer_->Seek(read_marker);
490 return GifDecoder::Status::kUnfinished;
491 }
492
493 gif_image->code_exp = code_size;
494 gif_image->data_pos = delegate_->GifCurrentPosition();
495 gif_image->image_GCE = nullptr;
496 if (graphic_control_extension_.get()) {
497 if (graphic_control_extension_->gce_flags.transparency) {
498 // Need to test that the color that is going to be transparent is actually
499 // in the palette being used.
500 if (graphic_control_extension_->trans_index >=
501 (2 << GetPaletteExp(gif_image.get()))) {
502 return GifDecoder::Status::kError;
503 }
504 }
505 gif_image->image_GCE = std::move(graphic_control_extension_);
506 graphic_control_extension_ = nullptr;
507 }
508
509 images_.push_back(std::move(gif_image));
510 SaveDecodingStatus(GIF_D_STATUS_IMG_DATA);
511 return GifDecoder::Status::kSuccess;
512 }
513
DecodingFailureAtTailCleanup(CFX_GifImage * gif_image)514 void CFX_GifContext::DecodingFailureAtTailCleanup(CFX_GifImage* gif_image) {
515 gif_image->row_buffer.clear();
516 SaveDecodingStatus(GIF_D_STATUS_TAIL);
517 }
518
ScanForTerminalMarker()519 bool CFX_GifContext::ScanForTerminalMarker() {
520 uint8_t data_size;
521
522 if (!ReadAllOrNone(&data_size, sizeof(data_size)))
523 return false;
524
525 while (data_size != GIF_BLOCK_TERMINAL) {
526 if (!input_buffer_->Seek(input_buffer_->GetPosition() + data_size) ||
527 !ReadAllOrNone(&data_size, sizeof(data_size))) {
528 return false;
529 }
530 }
531
532 return true;
533 }
534
GetPaletteExp(CFX_GifImage * gif_image) const535 uint8_t CFX_GifContext::GetPaletteExp(CFX_GifImage* gif_image) const {
536 return !gif_image->local_palettes.empty() ? gif_image->local_palette_exp
537 : global_palette_exp_;
538 }
539
540 } // namespace fxcodec
541