1 ///////////////////////////////////////////////////////////////////////////////
4 /// \brief LZ out window
6 // Authors: Igor Pavlov
9 // This file has been put into the public domain.
10 // You can do whatever you want with this file.
12 ///////////////////////////////////////////////////////////////////////////////
14 #ifndef LZMA_LZ_DECODER_H
15 #define LZMA_LZ_DECODER_H
21 /// Pointer to the dictionary buffer. It can be an allocated buffer
22 /// internal to liblzma, or it can a be a buffer given by the
23 /// application when in single-call mode (not implemented yet).
26 /// Write position in dictionary. The next byte will be written to
30 /// Indicates how full the dictionary is. This is used by
31 /// dict_is_distance_valid() to detect corrupt files that would
32 /// read beyond the beginning of the dictionary.
38 /// Size of the dictionary
41 /// True when dictionary should be reset before decoding more data.
49 const uint8_t *preset_dict
;
50 size_t preset_dict_size
;
55 /// Data specific to the LZ-based decoder
58 /// Function to decode from in[] to *dict
59 lzma_ret (*code
)(void *coder
,
60 lzma_dict
*restrict dict
, const uint8_t *restrict in
,
61 size_t *restrict in_pos
, size_t in_size
);
63 void (*reset
)(void *coder
, const void *options
);
65 /// Set the uncompressed size
66 void (*set_uncompressed
)(void *coder
, lzma_vli uncompressed_size
);
68 /// Free allocated resources
69 void (*end
)(void *coder
, const lzma_allocator
*allocator
);
74 #define LZMA_LZ_DECODER_INIT \
79 .set_uncompressed = NULL, \
84 extern lzma_ret
lzma_lz_decoder_init(lzma_next_coder
*next
,
85 const lzma_allocator
*allocator
,
86 const lzma_filter_info
*filters
,
87 lzma_ret (*lz_init
)(lzma_lz_decoder
*lz
,
88 const lzma_allocator
*allocator
, const void *options
,
89 lzma_lz_options
*lz_options
));
91 extern uint64_t lzma_lz_decoder_memusage(size_t dictionary_size
);
93 extern void lzma_lz_decoder_uncompressed(
94 void *coder
, lzma_vli uncompressed_size
);
97 //////////////////////
98 // Inline functions //
99 //////////////////////
101 /// Get a byte from the history buffer.
102 static inline uint8_t
103 dict_get(const lzma_dict
*const dict
, const uint32_t distance
)
105 return dict
->buf
[dict
->pos
- distance
- 1
106 + (distance
< dict
->pos
? 0 : dict
->size
)];
110 /// Test if dictionary is empty.
112 dict_is_empty(const lzma_dict
*const dict
)
114 return dict
->full
== 0;
118 /// Validate the match distance
120 dict_is_distance_valid(const lzma_dict
*const dict
, const size_t distance
)
122 return dict
->full
> distance
;
126 /// Repeat *len bytes at distance.
128 dict_repeat(lzma_dict
*dict
, uint32_t distance
, uint32_t *len
)
130 // Don't write past the end of the dictionary.
131 const size_t dict_avail
= dict
->limit
- dict
->pos
;
132 uint32_t left
= my_min(dict_avail
, *len
);
135 // Repeat a block of data from the history. Because memcpy() is faster
136 // than copying byte by byte in a loop, the copying process gets split
138 if (distance
< left
) {
139 // Source and target areas overlap, thus we can't use
140 // memcpy() nor even memmove() safely.
142 dict
->buf
[dict
->pos
] = dict_get(dict
, distance
);
144 } while (--left
> 0);
146 } else if (distance
< dict
->pos
) {
147 // The easiest and fastest case
148 memcpy(dict
->buf
+ dict
->pos
,
149 dict
->buf
+ dict
->pos
- distance
- 1,
154 // The bigger the dictionary, the more rare this
155 // case occurs. We need to "wrap" the dict, thus
156 // we might need two memcpy() to copy all the data.
157 assert(dict
->full
== dict
->size
);
158 const uint32_t copy_pos
159 = dict
->pos
- distance
- 1 + dict
->size
;
160 uint32_t copy_size
= dict
->size
- copy_pos
;
162 if (copy_size
< left
) {
163 memmove(dict
->buf
+ dict
->pos
, dict
->buf
+ copy_pos
,
165 dict
->pos
+= copy_size
;
166 copy_size
= left
- copy_size
;
167 memcpy(dict
->buf
+ dict
->pos
, dict
->buf
, copy_size
);
168 dict
->pos
+= copy_size
;
170 memmove(dict
->buf
+ dict
->pos
, dict
->buf
+ copy_pos
,
176 // Update how full the dictionary is.
177 if (dict
->full
< dict
->pos
)
178 dict
->full
= dict
->pos
;
180 return unlikely(*len
!= 0);
184 /// Puts one byte into the dictionary. Returns true if the dictionary was
185 /// already full and the byte couldn't be added.
187 dict_put(lzma_dict
*dict
, uint8_t byte
)
189 if (unlikely(dict
->pos
== dict
->limit
))
192 dict
->buf
[dict
->pos
++] = byte
;
194 if (dict
->pos
> dict
->full
)
195 dict
->full
= dict
->pos
;
201 /// Copies arbitrary amount of data into the dictionary.
203 dict_write(lzma_dict
*restrict dict
, const uint8_t *restrict in
,
204 size_t *restrict in_pos
, size_t in_size
,
205 size_t *restrict left
)
207 // NOTE: If we are being given more data than the size of the
208 // dictionary, it could be possible to optimize the LZ decoder
209 // so that not everything needs to go through the dictionary.
210 // This shouldn't be very common thing in practice though, and
211 // the slowdown of one extra memcpy() isn't bad compared to how
212 // much time it would have taken if the data were compressed.
214 if (in_size
- *in_pos
> *left
)
215 in_size
= *in_pos
+ *left
;
217 *left
-= lzma_bufcpy(in
, in_pos
, in_size
,
218 dict
->buf
, &dict
->pos
, dict
->limit
);
220 if (dict
->pos
> dict
->full
)
221 dict
->full
= dict
->pos
;
228 dict_reset(lzma_dict
*dict
)
230 dict
->need_reset
= true;