]> icculus.org git repositories - icculus/xz.git/blob - src/liblzma/common/filter_flags_decoder.c
Update the code to mostly match the new simpler file format
[icculus/xz.git] / src / liblzma / common / filter_flags_decoder.c
1 ///////////////////////////////////////////////////////////////////////////////
2 //
3 /// \file       filter_flags_decoder.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_decoder.h"
22
23
24 #ifdef HAVE_FILTER_SUBBLOCK
25 static lzma_ret
26 properties_subblock(lzma_options_filter *options, lzma_allocator *allocator,
27                 const uint8_t *props lzma_attribute((unused)),
28                 size_t prop_size lzma_attribute((unused)))
29 {
30         if (prop_size != 0)
31                 return LZMA_HEADER_ERROR;
32
33         options->options = lzma_alloc(
34                         sizeof(lzma_options_subblock), allocator);
35         if (options->options == NULL)
36                 return LZMA_MEM_ERROR;
37
38         ((lzma_options_subblock *)(options->options))->allow_subfilters = true;
39         return LZMA_OK;
40 }
41 #endif
42
43
44 #ifdef HAVE_FILTER_SIMPLE
45 static lzma_ret
46 properties_simple(lzma_options_filter *options, lzma_allocator *allocator,
47                 const uint8_t *props, size_t prop_size)
48 {
49         if (prop_size == 0)
50                 return LZMA_OK;
51
52         if (prop_size != 4)
53                 return LZMA_HEADER_ERROR;
54
55         lzma_options_simple *simple = lzma_alloc(
56                         sizeof(lzma_options_simple), allocator);
57         if (simple == NULL)
58                 return LZMA_MEM_ERROR;
59
60         simple->start_offset = integer_read_32(props);
61
62         // Don't leave an options structure allocated if start_offset is zero.
63         if (simple->start_offset == 0)
64                 lzma_free(simple, allocator);
65         else
66                 options->options = simple;
67
68         return LZMA_OK;
69 }
70 #endif
71
72
73 #ifdef HAVE_FILTER_DELTA
74 static lzma_ret
75 properties_delta(lzma_options_filter *options, lzma_allocator *allocator,
76                 const uint8_t *props, size_t prop_size)
77 {
78         if (prop_size != 1)
79                 return LZMA_HEADER_ERROR;
80
81         options->options = lzma_alloc(sizeof(lzma_options_delta), allocator);
82         if (options->options == NULL)
83                 return LZMA_MEM_ERROR;
84
85         ((lzma_options_delta *)(options->options))->distance
86                         = (uint32_t)(props[0]) + 1;
87
88         return LZMA_OK;
89 }
90 #endif
91
92
93 #ifdef HAVE_FILTER_LZMA
94 static lzma_ret
95 properties_lzma(lzma_options_filter *options, lzma_allocator *allocator,
96                 const uint8_t *props, size_t prop_size)
97 {
98         // LZMA properties are always two bytes (at least for now).
99         if (prop_size != 2)
100                 return LZMA_HEADER_ERROR;
101
102         lzma_options_lzma *lzma = lzma_alloc(
103                         sizeof(lzma_options_lzma), allocator);
104         if (lzma == NULL)
105                 return LZMA_MEM_ERROR;
106
107         // Decode lc, lp, and pb.
108         if (lzma_lzma_decode_properties(lzma, props[0]))
109                 goto error;
110
111         // Check that reserved bits are unset.
112         if (props[1] & 0xC0)
113                 goto error;
114
115         // Decode the dictionary size.
116         // FIXME The specification says that maximum is 4 GiB.
117         if (props[1] > 36)
118                 goto error;
119 #if LZMA_DICTIONARY_SIZE_MAX != UINT32_C(1) << 30
120 #       error Update the if()-condition a few lines
121 #       error above to match LZMA_DICTIONARY_SIZE_MAX.
122 #endif
123
124         lzma->dictionary_size = 2 | (props[1] & 1);
125         lzma->dictionary_size <<= props[1] / 2 + 11;
126
127         options->options = lzma;
128         return LZMA_OK;
129
130 error:
131         lzma_free(lzma, allocator);
132         return LZMA_HEADER_ERROR;
133 }
134 #endif
135
136
137 extern LZMA_API lzma_ret
138 lzma_filter_flags_decode(
139                 lzma_options_filter *options, lzma_allocator *allocator,
140                 const uint8_t *in, size_t *in_pos, size_t in_size)
141 {
142         // Set the pointer to NULL so the caller can always safely free it.
143         options->options = NULL;
144
145         // Filter ID
146         return_if_error(lzma_vli_decode(&options->id, NULL,
147                         in, in_pos, in_size));
148
149         // Size of Properties
150         lzma_vli prop_size;
151         return_if_error(lzma_vli_decode(&prop_size, NULL,
152                         in, in_pos, in_size));
153
154         // Check that we have enough input.
155         if (prop_size > in_size - *in_pos)
156                 return LZMA_DATA_ERROR;
157
158         // Determine the function to decode the properties.
159         lzma_ret (*get_properties)(lzma_options_filter *options,
160                         lzma_allocator *allocator, const uint8_t *props,
161                         size_t prop_size);
162
163         switch (options->id) {
164 #ifdef HAVE_FILTER_SUBBLOCK
165         case LZMA_FILTER_SUBBLOCK:
166                 get_properties = &properties_subblock;
167                 break;
168 #endif
169 #ifdef HAVE_FILTER_SIMPLE
170 #       ifdef HAVE_FILTER_X86
171         case LZMA_FILTER_X86:
172 #       endif
173 #       ifdef HAVE_FILTER_POWERPC
174         case LZMA_FILTER_POWERPC:
175 #       endif
176 #       ifdef HAVE_FILTER_IA64
177         case LZMA_FILTER_IA64:
178 #       endif
179 #       ifdef HAVE_FILTER_ARM
180         case LZMA_FILTER_ARM:
181 #       endif
182 #       ifdef HAVE_FILTER_ARMTHUMB
183         case LZMA_FILTER_ARMTHUMB:
184 #       endif
185 #       ifdef HAVE_FILTER_SPARC
186         case LZMA_FILTER_SPARC:
187 #       endif
188                 get_properties = &properties_simple;
189                 break;
190 #endif
191 #ifdef HAVE_FILTER_DELTA
192         case LZMA_FILTER_DELTA:
193                 get_properties = &properties_delta;
194                 break;
195 #endif
196 #ifdef HAVE_FILTER_LZMA
197         case LZMA_FILTER_LZMA:
198                 get_properties = &properties_lzma;
199                 break;
200 #endif
201         default:
202                 return LZMA_HEADER_ERROR;
203         }
204
205         const uint8_t *props = in + *in_pos;
206         *in_pos += prop_size;
207         return get_properties(options, allocator, props, prop_size);
208 }