Home | History | Annotate | Download | only in gif
      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 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
      6 
      7 #include "core/fxcodec/gif/cfx_lzwdecompressor.h"
      8 
      9 #include <algorithm>
     10 #include <memory>
     11 #include <utility>
     12 
     13 #include "core/fxcodec/lbmp/fx_bmp.h"
     14 #include "third_party/base/numerics/safe_math.h"
     15 #include "third_party/base/ptr_util.h"
     16 #include "third_party/base/stl_util.h"
     17 
     18 std::unique_ptr<CFX_LZWDecompressor> CFX_LZWDecompressor::Create(
     19     uint8_t color_exp,
     20     uint8_t code_exp) {
     21   // color_exp generates 2^(n + 1) codes, where as the code_exp reserves 2^n.
     22   // This is a quirk of the GIF spec.
     23   if (code_exp > GIF_MAX_LZW_EXP || code_exp < color_exp + 1)
     24     return nullptr;
     25   return std::unique_ptr<CFX_LZWDecompressor>(
     26       new CFX_LZWDecompressor(color_exp, code_exp));
     27 }
     28 
     29 CFX_LZWDecompressor::CFX_LZWDecompressor(uint8_t color_exp, uint8_t code_exp)
     30     : code_size_(code_exp),
     31       code_size_cur_(0),
     32       code_color_end_(static_cast<uint16_t>(1 << (color_exp + 1))),
     33       code_clear_(static_cast<uint16_t>(1 << code_exp)),
     34       code_end_(static_cast<uint16_t>((1 << code_exp) + 1)),
     35       code_next_(0),
     36       code_first_(0),
     37       code_old_(0),
     38       next_in_(nullptr),
     39       avail_in_(0),
     40       bits_left_(0),
     41       code_store_(0) {}
     42 
     43 CFX_LZWDecompressor::~CFX_LZWDecompressor() {}
     44 
     45 CFX_GifDecodeStatus CFX_LZWDecompressor::Decode(uint8_t* src_buf,
     46                                                 uint32_t src_size,
     47                                                 uint8_t* des_buf,
     48                                                 uint32_t* des_size) {
     49   if (!src_buf || src_size == 0 || !des_buf || !des_size)
     50     return CFX_GifDecodeStatus::Error;
     51 
     52   if (*des_size == 0)
     53     return CFX_GifDecodeStatus::InsufficientDestSize;
     54 
     55   next_in_ = src_buf;
     56   avail_in_ = src_size;
     57 
     58   ClearTable();
     59 
     60   uint32_t i = 0;
     61   if (decompressed_next_ != 0) {
     62     uint32_t extracted_size = ExtractData(des_buf, *des_size);
     63     if (decompressed_next_ != 0)
     64       return CFX_GifDecodeStatus::InsufficientDestSize;
     65 
     66     des_buf += extracted_size;
     67     i += extracted_size;
     68   }
     69 
     70   while (i <= *des_size && (avail_in_ > 0 || bits_left_ >= code_size_cur_)) {
     71     if (code_size_cur_ > GIF_MAX_LZW_EXP)
     72       return CFX_GifDecodeStatus::Error;
     73 
     74     if (avail_in_ > 0) {
     75       if (bits_left_ > 31)
     76         return CFX_GifDecodeStatus::Error;
     77 
     78       pdfium::base::CheckedNumeric<uint32_t> safe_code = *next_in_++;
     79       safe_code <<= bits_left_;
     80       safe_code |= code_store_;
     81       if (!safe_code.IsValid())
     82         return CFX_GifDecodeStatus::Error;
     83 
     84       code_store_ = safe_code.ValueOrDie();
     85       --avail_in_;
     86       bits_left_ += 8;
     87     }
     88 
     89     while (bits_left_ >= code_size_cur_) {
     90       uint16_t code =
     91           static_cast<uint16_t>(code_store_) & ((1 << code_size_cur_) - 1);
     92       code_store_ >>= code_size_cur_;
     93       bits_left_ -= code_size_cur_;
     94       if (code == code_clear_) {
     95         ClearTable();
     96         continue;
     97       }
     98       if (code == code_end_) {
     99         *des_size = i;
    100         return CFX_GifDecodeStatus::Success;
    101       }
    102 
    103       if (code_old_ != static_cast<uint16_t>(-1)) {
    104         if (code_next_ < GIF_MAX_LZW_CODE) {
    105           if (code == code_next_) {
    106             AddCode(code_old_, code_first_);
    107             if (!DecodeString(code))
    108               return CFX_GifDecodeStatus::Error;
    109           } else if (code > code_next_) {
    110             return CFX_GifDecodeStatus::Error;
    111           } else {
    112             if (!DecodeString(code))
    113               return CFX_GifDecodeStatus::Error;
    114 
    115             uint8_t append_char = decompressed_[decompressed_next_ - 1];
    116             AddCode(code_old_, append_char);
    117           }
    118         }
    119       } else {
    120         if (!DecodeString(code))
    121           return CFX_GifDecodeStatus::Error;
    122       }
    123 
    124       code_old_ = code;
    125       uint32_t extracted_size = ExtractData(des_buf, *des_size - i);
    126       if (decompressed_next_ != 0)
    127         return CFX_GifDecodeStatus::InsufficientDestSize;
    128 
    129       des_buf += extracted_size;
    130       i += extracted_size;
    131     }
    132   }
    133 
    134   if (avail_in_ != 0)
    135     return CFX_GifDecodeStatus::Error;
    136 
    137   *des_size = i;
    138   return CFX_GifDecodeStatus::Unfinished;
    139 }
    140 
    141 void CFX_LZWDecompressor::ClearTable() {
    142   code_size_cur_ = code_size_ + 1;
    143   code_next_ = code_end_ + 1;
    144   code_old_ = static_cast<uint16_t>(-1);
    145   memset(code_table_, 0, sizeof(code_table_));
    146   for (uint16_t i = 0; i < code_clear_; i++)
    147     code_table_[i].suffix = static_cast<uint8_t>(i);
    148   decompressed_.resize(code_next_ - code_clear_ + 1);
    149   decompressed_next_ = 0;
    150 }
    151 
    152 void CFX_LZWDecompressor::AddCode(uint16_t prefix_code, uint8_t append_char) {
    153   if (code_next_ == GIF_MAX_LZW_CODE)
    154     return;
    155 
    156   code_table_[code_next_].prefix = prefix_code;
    157   code_table_[code_next_].suffix = append_char;
    158   if (++code_next_ < GIF_MAX_LZW_CODE) {
    159     if (code_next_ >> code_size_cur_)
    160       code_size_cur_++;
    161   }
    162 }
    163 
    164 bool CFX_LZWDecompressor::DecodeString(uint16_t code) {
    165   decompressed_.resize(code_next_ - code_clear_ + 1);
    166   decompressed_next_ = 0;
    167 
    168   while (code >= code_clear_ && code <= code_next_) {
    169     if (code == code_table_[code].prefix ||
    170         decompressed_next_ >= decompressed_.size())
    171       return false;
    172 
    173     decompressed_[decompressed_next_++] = code_table_[code].suffix;
    174     code = code_table_[code].prefix;
    175   }
    176 
    177   if (code >= code_color_end_)
    178     return false;
    179 
    180   decompressed_[decompressed_next_++] = static_cast<uint8_t>(code);
    181   code_first_ = static_cast<uint8_t>(code);
    182   return true;
    183 }
    184 
    185 uint32_t CFX_LZWDecompressor::ExtractData(uint8_t* des_buf, uint32_t des_size) {
    186   if (des_size == 0)
    187     return 0;
    188 
    189   uint32_t copy_size = des_size <= decompressed_next_
    190                            ? des_size
    191                            : static_cast<uint32_t>(decompressed_next_);
    192   std::reverse_copy(decompressed_.data() + decompressed_next_ - copy_size,
    193                     decompressed_.data() + decompressed_next_, des_buf);
    194   decompressed_next_ -= copy_size;
    195   return copy_size;
    196 }
    197