]> icculus.org git repositories - icculus/xz.git/blob - src/liblzma/common/alone_decoder.c
Remove some redundant code from LZMA encoder.
[icculus/xz.git] / src / liblzma / common / alone_decoder.c
1 ///////////////////////////////////////////////////////////////////////////////
2 //
3 /// \file       alone_decoder.c
4 /// \brief      Decoder for LZMA_Alone files
5 //
6 //  Copyright (C) 2007 Lasse Collin
7 //
8 //  This library is free software; you can redistribute it and/or
9 //  modify it under the terms of the GNU Lesser General Public
10 //  License as published by the Free Software Foundation; either
11 //  version 2.1 of the License, or (at your option) any later version.
12 //
13 //  This library is distributed in the hope that it will be useful,
14 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
15 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16 //  Lesser General Public License for more details.
17 //
18 ///////////////////////////////////////////////////////////////////////////////
19
20 #include "alone_decoder.h"
21 #include "lzma_decoder.h"
22
23
24 struct lzma_coder_s {
25         lzma_next_coder next;
26
27         enum {
28                 SEQ_PROPERTIES,
29                 SEQ_DICTIONARY_SIZE,
30                 SEQ_UNCOMPRESSED_SIZE,
31                 SEQ_CODER_INIT,
32                 SEQ_CODE,
33         } sequence;
34
35         /// Position in the header fields
36         size_t pos;
37
38         /// Uncompressed size decoded from the header
39         lzma_vli uncompressed_size;
40
41         /// Options decoded from the header needed to initialize
42         /// the LZMA decoder
43         lzma_options_lzma options;
44 };
45
46
47 static lzma_ret
48 alone_decode(lzma_coder *coder,
49                 lzma_allocator *allocator lzma_attribute((unused)),
50                 const uint8_t *restrict in, size_t *restrict in_pos,
51                 size_t in_size, uint8_t *restrict out,
52                 size_t *restrict out_pos, size_t out_size,
53                 lzma_action action)
54 {
55         while (*out_pos < out_size
56                         && (coder->sequence == SEQ_CODE || *in_pos < in_size))
57         switch (coder->sequence) {
58         case SEQ_PROPERTIES:
59                 if (lzma_lzma_decode_properties(&coder->options, in[*in_pos]))
60                         return LZMA_FORMAT_ERROR;
61
62                 coder->sequence = SEQ_DICTIONARY_SIZE;
63                 ++*in_pos;
64                 break;
65
66         case SEQ_DICTIONARY_SIZE:
67                 coder->options.dictionary_size
68                                 |= (size_t)(in[*in_pos]) << (coder->pos * 8);
69
70                 if (++coder->pos == 4) {
71                         if (coder->options.dictionary_size
72                                         < LZMA_DICTIONARY_SIZE_MIN
73                                         || coder->options.dictionary_size
74                                         > LZMA_DICTIONARY_SIZE_MAX)
75                                 return LZMA_FORMAT_ERROR;
76
77                         // A hack to ditch tons of false positives: We allow
78                         // only dictionary sizes that are 2^n or 2^n + 2^(n-1).
79                         // LZMA_Alone created only files with 2^n, but accepts
80                         // any dictionary size. If someone complains, this
81                         // will be reconsidered.
82                         uint32_t d = coder->options.dictionary_size - 1;
83                         d |= d >> 2;
84                         d |= d >> 3;
85                         d |= d >> 4;
86                         d |= d >> 8;
87                         d |= d >> 16;
88                         ++d;
89
90                         if (d != coder->options.dictionary_size)
91                                 return LZMA_FORMAT_ERROR;
92
93                         coder->pos = 0;
94                         coder->sequence = SEQ_UNCOMPRESSED_SIZE;
95                 }
96
97                 ++*in_pos;
98                 break;
99
100         case SEQ_UNCOMPRESSED_SIZE:
101                 coder->uncompressed_size
102                                 |= (lzma_vli)(in[*in_pos]) << (coder->pos * 8);
103
104                 if (++coder->pos == 8) {
105                         // Another hack to ditch false positives: Assume that
106                         // if the uncompressed size is known, it must be less
107                         // than 256 GiB. Again, if someone complains, this
108                         // will be reconsidered.
109                         if (coder->uncompressed_size != LZMA_VLI_VALUE_UNKNOWN
110                                         && coder->uncompressed_size
111                                                 >= (LZMA_VLI_C(1) << 38))
112                                 return LZMA_FORMAT_ERROR;
113
114                         coder->pos = 0;
115                         coder->sequence = SEQ_CODER_INIT;
116                 }
117
118                 ++*in_pos;
119                 break;
120
121         case SEQ_CODER_INIT: {
122                 // Two is enough because there won't be implicit filters.
123                 lzma_filter_info filters[2] = {
124                         {
125                                 .init = &lzma_lzma_decoder_init,
126                                 .options = &coder->options,
127                         }, {
128                                 .init = NULL,
129                         }
130                 };
131
132                 const lzma_ret ret = lzma_next_filter_init(&coder->next,
133                                 allocator, filters);
134                 if (ret != LZMA_OK)
135                         return ret;
136
137                 // Use a hack to set the uncompressed size.
138                 lzma_lzma_decoder_uncompressed_size(&coder->next,
139                                 coder->uncompressed_size);
140
141                 coder->sequence = SEQ_CODE;
142         }
143
144         // Fall through
145
146         case SEQ_CODE: {
147                 return coder->next.code(coder->next.coder,
148                                 allocator, in, in_pos, in_size,
149                                 out, out_pos, out_size, action);
150         }
151
152         default:
153                 return LZMA_PROG_ERROR;
154         }
155
156         return LZMA_OK;
157 }
158
159
160 static void
161 alone_decoder_end(lzma_coder *coder, lzma_allocator *allocator)
162 {
163         lzma_next_coder_end(&coder->next, allocator);
164         lzma_free(coder, allocator);
165         return;
166 }
167
168
169 static lzma_ret
170 alone_decoder_init(lzma_next_coder *next, lzma_allocator *allocator)
171 {
172         if (next->coder == NULL) {
173                 next->coder = lzma_alloc(sizeof(lzma_coder), allocator);
174                 if (next->coder == NULL)
175                         return LZMA_MEM_ERROR;
176
177                 next->code = &alone_decode;
178                 next->end = &alone_decoder_end;
179                 next->coder->next = LZMA_NEXT_CODER_INIT;
180         }
181
182         next->coder->sequence = SEQ_PROPERTIES;
183         next->coder->pos = 0;
184         next->coder->options.dictionary_size = 0;
185         next->coder->uncompressed_size = 0;
186
187         return LZMA_OK;
188 }
189
190
191 extern lzma_ret
192 lzma_alone_decoder_init(lzma_next_coder *next, lzma_allocator *allocator)
193 {
194         lzma_next_coder_init0(alone_decoder_init, next, allocator);
195 }
196
197
198 extern LZMA_API lzma_ret
199 lzma_alone_decoder(lzma_stream *strm)
200 {
201         lzma_next_strm_init0(strm, alone_decoder_init);
202
203         strm->internal->supported_actions[LZMA_RUN] = true;
204         strm->internal->supported_actions[LZMA_SYNC_FLUSH] = true;
205
206         return LZMA_OK;
207 }