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