]> icculus.org git repositories - icculus/xz.git/blob - src/liblzma/common/filter_flags_encoder.c
Update the code to mostly match the new simpler file format
[icculus/xz.git] / src / liblzma / common / filter_flags_encoder.c
1 ///////////////////////////////////////////////////////////////////////////////
2 //
3 /// \file       filter_flags_encoder.c
4 /// \brief      Decodes a Filter Flags field
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 "common.h"
21 #include "lzma_encoder.h"
22 #include "fastpos.h"
23
24
25 /// Calculate the size of the Filter Properties field
26 static lzma_ret
27 get_properties_size(uint32_t *size, const lzma_options_filter *options)
28 {
29         lzma_ret ret = LZMA_OK;
30
31         switch (options->id) {
32 #ifdef HAVE_FILTER_SUBBLOCK
33         case LZMA_FILTER_SUBBLOCK:
34                 *size = 0;
35                 break;
36 #endif
37
38 #ifdef HAVE_FILTER_SIMPLE
39 #       ifdef HAVE_FILTER_X86
40         case LZMA_FILTER_X86:
41 #       endif
42 #       ifdef HAVE_FILTER_POWERPC
43         case LZMA_FILTER_POWERPC:
44 #       endif
45 #       ifdef HAVE_FILTER_IA64
46         case LZMA_FILTER_IA64:
47 #       endif
48 #       ifdef HAVE_FILTER_ARM
49         case LZMA_FILTER_ARM:
50 #       endif
51 #       ifdef HAVE_FILTER_ARMTHUMB
52         case LZMA_FILTER_ARMTHUMB:
53 #       endif
54 #       ifdef HAVE_FILTER_SPARC
55         case LZMA_FILTER_SPARC:
56 #       endif
57                 if (options->options == NULL || ((const lzma_options_simple *)(
58                                 options->options))->start_offset == 0)
59                         *size = 0;
60                 else
61                         *size = 4;
62                 break;
63 #endif
64
65 #ifdef HAVE_FILTER_DELTA
66         case LZMA_FILTER_DELTA:
67                 *size = 1;
68                 break;
69 #endif
70
71 #ifdef HAVE_FILTER_LZMA
72         case LZMA_FILTER_LZMA:
73                 *size = 2;
74                 break;
75 #endif
76
77         default:
78                 // Unknown filter - if the Filter ID is a proper VLI,
79                 // return LZMA_HEADER_ERROR instead of LZMA_PROG_ERROR,
80                 // because it's possible that we just don't have support
81                 // compiled in for the requested filter.
82                 ret = options->id <= LZMA_VLI_VALUE_MAX
83                                 ? LZMA_HEADER_ERROR : LZMA_PROG_ERROR;
84                 break;
85         }
86
87         return ret;
88 }
89
90
91 extern LZMA_API lzma_ret
92 lzma_filter_flags_size(uint32_t *size, const lzma_options_filter *options)
93 {
94         // Get size of Filter Properties. This also validates the Filter ID.
95         uint32_t prop_size;
96         return_if_error(get_properties_size(&prop_size, options));
97
98         // Calculate the size of the Filter ID and Size of Properties fields.
99         // These cannot fail since get_properties_size() already succeeded.
100         *size = lzma_vli_size(options->id) + lzma_vli_size(prop_size)
101                         + prop_size;
102
103         return LZMA_OK;
104 }
105
106
107 #ifdef HAVE_FILTER_SIMPLE
108 /// Encodes Filter Properties of the so called simple filters
109 static lzma_ret
110 properties_simple(uint8_t *out, size_t *out_pos, size_t out_size,
111                 const lzma_options_simple *options)
112 {
113         if (options == NULL || options->start_offset == 0)
114                 return LZMA_OK;
115
116         if (out_size - *out_pos < 4)
117                 return LZMA_PROG_ERROR;
118
119         integer_write_32(out + *out_pos, options->start_offset);
120         *out_pos += 4;
121
122         return LZMA_OK;
123 }
124 #endif
125
126
127 #ifdef HAVE_FILTER_DELTA
128 /// Encodes Filter Properties of the Delta filter
129 static lzma_ret
130 properties_delta(uint8_t *out, size_t *out_pos, size_t out_size,
131                 const lzma_options_delta *options)
132 {
133         if (options == NULL)
134                 return LZMA_PROG_ERROR;
135
136         // It's possible that newer liblzma versions will support larger
137         // distance values.
138         if (options->distance < LZMA_DELTA_DISTANCE_MIN
139                         || options->distance > LZMA_DELTA_DISTANCE_MAX)
140                 return LZMA_HEADER_ERROR;
141
142         if (out_size - *out_pos < 1)
143                 return LZMA_PROG_ERROR;
144
145         out[*out_pos] = options->distance - LZMA_DELTA_DISTANCE_MIN;
146         ++*out_pos;
147
148         return LZMA_OK;
149 }
150 #endif
151
152
153 #ifdef HAVE_FILTER_LZMA
154 /// Encodes LZMA Properties and Dictionary Flags (two bytes)
155 static lzma_ret
156 properties_lzma(uint8_t *out, size_t *out_pos, size_t out_size,
157                 const lzma_options_lzma *options)
158 {
159         if (options == NULL)
160                 return LZMA_PROG_ERROR;
161
162         if (out_size - *out_pos < 2)
163                 return LZMA_PROG_ERROR;
164
165         // LZMA Properties
166         if (lzma_lzma_encode_properties(options, out + *out_pos))
167                 return LZMA_HEADER_ERROR;
168
169         ++*out_pos;
170
171         // Dictionary flags
172         //
173         // Dictionary size is encoded using similar encoding that is used
174         // internally by LZMA.
175         //
176         // This won't work if dictionary size can be zero:
177 #       if LZMA_DICTIONARY_SIZE_MIN < 1
178 #               error LZMA_DICTIONARY_SIZE_MIN cannot be zero.
179 #       endif
180
181         uint32_t d = options->dictionary_size;
182
183         // Validate it:
184         if (d < LZMA_DICTIONARY_SIZE_MIN || d > LZMA_DICTIONARY_SIZE_MAX)
185                 return LZMA_HEADER_ERROR;
186
187         // Round up to to the next 2^n or 2^n + 2^(n - 1) depending on which
188         // one is the next:
189         --d;
190         d |= d >> 2;
191         d |= d >> 3;
192         d |= d >> 4;
193         d |= d >> 8;
194         d |= d >> 16;
195         ++d;
196
197         // Get the highest two bits using the proper encoding:
198         out[*out_pos] = get_pos_slot(d) - 24;
199         ++*out_pos;
200
201         return LZMA_OK;
202 }
203 #endif
204
205
206 extern LZMA_API lzma_ret
207 lzma_filter_flags_encode(uint8_t *out, size_t *out_pos, size_t out_size,
208                 const lzma_options_filter *options)
209 {
210         // Minimum output is one byte (everything fits into Misc).
211         // The caller should have checked that there is enough output space,
212         // so we return LZMA_PROG_ERROR instead of LZMA_BUF_ERROR.
213         if (*out_pos >= out_size)
214                 return LZMA_PROG_ERROR;
215
216         // Get size of Filter Properties.
217         uint32_t prop_size;
218         return_if_error(get_properties_size(&prop_size, options));
219
220         // Filter ID
221         return_if_error(lzma_vli_encode(options->id, NULL,
222                         out, out_pos, out_size));
223
224         // Size of Properties
225         return_if_error(lzma_vli_encode(prop_size, NULL,
226                         out, out_pos, out_size));
227
228         // Filter Properties
229         lzma_ret ret;
230         switch (options->id) {
231 #ifdef HAVE_FILTER_SUBBLOCK
232         case LZMA_FILTER_SUBBLOCK:
233                 assert(prop_size == 0);
234                 ret = LZMA_OK;
235                 break;
236 #endif
237
238 #ifdef HAVE_FILTER_SIMPLE
239 #       ifdef HAVE_FILTER_X86
240         case LZMA_FILTER_X86:
241 #       endif
242 #       ifdef HAVE_FILTER_POWERPC
243         case LZMA_FILTER_POWERPC:
244 #       endif
245 #       ifdef HAVE_FILTER_IA64
246         case LZMA_FILTER_IA64:
247 #       endif
248 #       ifdef HAVE_FILTER_ARM
249         case LZMA_FILTER_ARM:
250 #       endif
251 #       ifdef HAVE_FILTER_ARMTHUMB
252         case LZMA_FILTER_ARMTHUMB:
253 #       endif
254 #       ifdef HAVE_FILTER_SPARC
255         case LZMA_FILTER_SPARC:
256 #       endif
257                 ret = properties_simple(out, out_pos, out_size,
258                                 options->options);
259                 break;
260 #endif
261
262 #ifdef HAVE_FILTER_DELTA
263         case LZMA_FILTER_DELTA:
264                 ret = properties_delta(out, out_pos, out_size,
265                                 options->options);
266                 break;
267 #endif
268
269 #ifdef HAVE_FILTER_LZMA
270         case LZMA_FILTER_LZMA:
271                 ret = properties_lzma(out, out_pos, out_size,
272                                 options->options);
273                 break;
274 #endif
275
276         default:
277                 assert(0);
278                 ret = LZMA_PROG_ERROR;
279                 break;
280         }
281
282         return ret;
283 }