Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
lzw_decompressor.cpp
Go to the documentation of this file.
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/lzw_decompressor.h"
8
9#include <string.h>
10
11#include <algorithm>
12#include <memory>
13#include <utility>
14
15#include "core/fxcrt/fx_safe_types.h"
16#include "third_party/base/memory/ptr_util.h"
17
18namespace fxcodec {
19
20std::unique_ptr<LZWDecompressor> LZWDecompressor::Create(uint8_t color_exp,
21 uint8_t code_exp) {
22 // |color_exp| generates 2^(n + 1) codes, where as the code_exp reserves 2^n.
23 // This is a quirk of the GIF spec.
24 if (code_exp > GIF_MAX_LZW_EXP || code_exp < color_exp + 1)
25 return nullptr;
26
27 // Private ctor.
28 return pdfium::WrapUnique(new LZWDecompressor(color_exp, code_exp));
29}
30
31LZWDecompressor::LZWDecompressor(uint8_t color_exp, uint8_t code_exp)
32 : code_size_(code_exp),
33 code_color_end_(static_cast<uint16_t>(1 << (color_exp + 1))),
34 code_clear_(static_cast<uint16_t>(1 << code_exp)),
35 code_end_(static_cast<uint16_t>((1 << code_exp) + 1)) {
36 ClearTable();
37}
38
40
41void LZWDecompressor::SetSource(const uint8_t* src_buf, uint32_t src_size) {
42 next_in_ = src_buf;
43 avail_in_ = src_size;
44}
45
47 uint32_t* dest_size) {
48 if (!next_in_ || !dest_buf || !dest_size)
49 return Status::kError;
50
51 if (avail_in_ == 0)
53
54 if (*dest_size == 0)
56
57 uint32_t i = 0;
58 if (decompressed_next_ != 0) {
59 uint32_t extracted_size = ExtractData(dest_buf, *dest_size);
60 if (decompressed_next_ != 0)
62
63 dest_buf += extracted_size;
64 i += extracted_size;
65 }
66
67 while (i <= *dest_size && (avail_in_ > 0 || bits_left_ >= code_size_cur_)) {
68 if (code_size_cur_ > GIF_MAX_LZW_EXP)
69 return Status::kError;
70
71 if (avail_in_ > 0) {
72 if (bits_left_ > 31)
73 return Status::kError;
74
75 FX_SAFE_UINT32 safe_code = *next_in_++;
76 safe_code <<= bits_left_;
77 safe_code |= code_store_;
78 if (!safe_code.IsValid())
79 return Status::kError;
80
81 code_store_ = safe_code.ValueOrDie();
82 --avail_in_;
83 bits_left_ += 8;
84 }
85
86 while (bits_left_ >= code_size_cur_) {
87 uint16_t code =
88 static_cast<uint16_t>(code_store_) & ((1 << code_size_cur_) - 1);
89 code_store_ >>= code_size_cur_;
90 bits_left_ -= code_size_cur_;
91 if (code == code_clear_) {
92 ClearTable();
93 continue;
94 }
95 if (code == code_end_) {
96 *dest_size = i;
97 return Status::kSuccess;
98 }
99
100 if (code_old_ != static_cast<uint16_t>(-1)) {
101 if (code_next_ < GIF_MAX_LZW_CODE) {
102 if (code == code_next_) {
103 AddCode(code_old_, code_first_);
104 if (!DecodeString(code))
105 return Status::kError;
106 } else if (code > code_next_) {
107 return Status::kError;
108 } else {
109 if (!DecodeString(code))
110 return Status::kError;
111
112 uint8_t append_char = decompressed_[decompressed_next_ - 1];
113 AddCode(code_old_, append_char);
114 }
115 }
116 } else {
117 if (!DecodeString(code))
118 return Status::kError;
119 }
120
121 code_old_ = code;
122 uint32_t extracted_size = ExtractData(dest_buf, *dest_size - i);
123 if (decompressed_next_ != 0)
125
126 dest_buf += extracted_size;
127 i += extracted_size;
128 }
129 }
130
131 if (avail_in_ != 0)
132 return Status::kError;
133
134 *dest_size = i;
135 return Status::kUnfinished;
136}
137
138void LZWDecompressor::ClearTable() {
139 code_size_cur_ = code_size_ + 1;
140 code_next_ = code_end_ + 1;
141 code_old_ = static_cast<uint16_t>(-1);
142 memset(code_table_, 0, sizeof(code_table_));
143 for (uint16_t i = 0; i < code_clear_; i++)
144 code_table_[i].suffix = static_cast<uint8_t>(i);
145 decompressed_.resize(code_next_ - code_clear_ + 1);
146 decompressed_next_ = 0;
147}
148
149void LZWDecompressor::AddCode(uint16_t prefix_code, uint8_t append_char) {
150 if (code_next_ == GIF_MAX_LZW_CODE)
151 return;
152
153 code_table_[code_next_].prefix = prefix_code;
154 code_table_[code_next_].suffix = append_char;
155 if (++code_next_ < GIF_MAX_LZW_CODE) {
156 if (code_next_ >> code_size_cur_)
157 code_size_cur_++;
158 }
159}
160
161bool LZWDecompressor::DecodeString(uint16_t code) {
162 decompressed_.resize(code_next_ - code_clear_ + 1);
163 decompressed_next_ = 0;
164
165 while (code >= code_clear_ && code <= code_next_) {
166 if (code == code_table_[code].prefix ||
167 decompressed_next_ >= decompressed_.size())
168 return false;
169
170 decompressed_[decompressed_next_++] = code_table_[code].suffix;
171 code = code_table_[code].prefix;
172 }
173
174 if (code >= code_color_end_)
175 return false;
176
177 decompressed_[decompressed_next_++] = static_cast<uint8_t>(code);
178 code_first_ = static_cast<uint8_t>(code);
179 return true;
180}
181
182uint32_t LZWDecompressor::ExtractData(uint8_t* dest_buf, uint32_t dest_size) {
183 if (dest_size == 0)
184 return 0;
185
186 uint32_t copy_size = dest_size <= decompressed_next_
187 ? dest_size
188 : static_cast<uint32_t>(decompressed_next_);
189 std::reverse_copy(decompressed_.data() + decompressed_next_ - copy_size,
190 decompressed_.data() + decompressed_next_, dest_buf);
191 decompressed_next_ -= copy_size;
192 return copy_size;
193}
194
195} // namespace fxcodec
#define GIF_MAX_LZW_CODE
Definition cfx_gif.h:28
#define GIF_MAX_LZW_EXP
Definition cfx_gif.h:27
Status Decode(uint8_t *dest_buf, uint32_t *dest_size)
void SetSource(const uint8_t *src_buf, uint32_t src_size)