• 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 // 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