]> icculus.org git repositories - icculus/xz.git/blob - src/liblzma/common/raw_common.c
Remove two redundant validity checks from the LZMA decoder.
[icculus/xz.git] / src / liblzma / common / raw_common.c
1 ///////////////////////////////////////////////////////////////////////////////
2 //
3 /// \file       raw_common.c
4 /// \brief      Stuff shared between raw encoder and raw decoder
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 "raw_common.h"
21
22
23 /// \brief      Prepares the filter chain
24 ///
25 /// Prepares the filter chain by setting uncompressed sizes for each filter,
26 /// and adding implicit Subblock filter when needed.
27 ///
28 /// \return     true if error occurred, false on success.
29 ///
30 static bool
31 prepare(lzma_vli *id, lzma_vli *uncompressed_size, bool allow_implicit)
32 {
33         bool needs_end_of_input = false;
34
35         switch (id[0]) {
36         case LZMA_FILTER_COPY:
37         case LZMA_FILTER_X86:
38         case LZMA_FILTER_POWERPC:
39         case LZMA_FILTER_IA64:
40         case LZMA_FILTER_ARM:
41         case LZMA_FILTER_ARMTHUMB:
42         case LZMA_FILTER_SPARC:
43         case LZMA_FILTER_DELTA:
44                 uncompressed_size[1] = uncompressed_size[0];
45                 needs_end_of_input = true;
46                 break;
47
48         case LZMA_FILTER_SUBBLOCK:
49         case LZMA_FILTER_LZMA:
50                 // These change the size of the data unpredictably.
51                 uncompressed_size[1] = LZMA_VLI_VALUE_UNKNOWN;
52                 break;
53
54         case LZMA_FILTER_SUBBLOCK_HELPER:
55                 uncompressed_size[1] = uncompressed_size[0];
56                 break;
57
58         default:
59                 // Unknown filter.
60                 return true;
61         }
62
63         // Is this the last filter in the chain?
64         if (id[1] == LZMA_VLI_VALUE_UNKNOWN) {
65                 if (needs_end_of_input && allow_implicit
66                                 && uncompressed_size[0]
67                                         == LZMA_VLI_VALUE_UNKNOWN) {
68                         // Add implicit Subblock filter.
69                         id[1] = LZMA_FILTER_SUBBLOCK;
70                         uncompressed_size[1] = LZMA_VLI_VALUE_UNKNOWN;
71                         id[2] = LZMA_VLI_VALUE_UNKNOWN;
72                 }
73
74                 return false;
75         }
76
77         return prepare(id + 1, uncompressed_size + 1, allow_implicit);
78 }
79
80
81 extern lzma_ret
82 lzma_raw_coder_init(lzma_next_coder *next, lzma_allocator *allocator,
83                 const lzma_options_filter *options, lzma_vli uncompressed_size,
84                 lzma_init_function (*get_function)(lzma_vli id),
85                 bool allow_implicit, bool is_encoder)
86 {
87         if (options == NULL || !lzma_vli_is_valid(uncompressed_size))
88                 return LZMA_PROG_ERROR;
89
90         // Count the number of filters in the chain.
91         size_t count = 0;
92         while (options[count].id != LZMA_VLI_VALUE_UNKNOWN)
93                 ++count;
94
95         // Allocate enough space from the stack for IDs and uncompressed
96         // sizes. We need two extra: possible implicit Subblock and end
97         // of array indicator.
98         lzma_vli ids[count + 2];
99         lzma_vli uncompressed_sizes[count + 2];
100         bool using_implicit = false;
101
102         uncompressed_sizes[0] = uncompressed_size;
103
104         if (count == 0) {
105                 if (!allow_implicit)
106                         return LZMA_PROG_ERROR;
107
108                 count = 1;
109                 using_implicit = true;
110
111                 // Special case: no filters were specified, so an implicit
112                 // Copy or Subblock filter is used.
113                 if (uncompressed_size == LZMA_VLI_VALUE_UNKNOWN)
114                         ids[0] = LZMA_FILTER_SUBBLOCK;
115                 else
116                         ids[0] = LZMA_FILTER_COPY;
117
118                 ids[1] = LZMA_VLI_VALUE_UNKNOWN;
119
120         } else {
121                 // Prepare the ids[] and uncompressed_sizes[].
122                 for (size_t i = 0; i < count; ++i)
123                         ids[i] = options[i].id;
124
125                 ids[count] = LZMA_VLI_VALUE_UNKNOWN;
126
127                 if (prepare(ids, uncompressed_sizes, allow_implicit))
128                         return LZMA_HEADER_ERROR;
129
130                 // Check if implicit Subblock filter was added.
131                 if (ids[count] != LZMA_VLI_VALUE_UNKNOWN) {
132                         assert(ids[count] == LZMA_FILTER_SUBBLOCK);
133                         ++count;
134                         using_implicit = true;
135                 }
136         }
137
138         // Set the filter functions, and copy uncompressed sizes and options.
139         lzma_filter_info filters[count + 1];
140         if (is_encoder) {
141                 for (size_t i = 0; i < count; ++i) {
142                         // The order of the filters is reversed in the
143                         // encoder. It allows more efficient handling
144                         // of the uncompressed data.
145                         const size_t j = count - i - 1;
146
147                         filters[j].init = get_function(ids[i]);
148                         if (filters[j].init == NULL)
149                                 return LZMA_HEADER_ERROR;
150
151                         filters[j].options = options[i].options;
152                         filters[j].uncompressed_size = uncompressed_sizes[i];
153                 }
154
155                 if (using_implicit)
156                         filters[0].options = NULL;
157
158         } else {
159                 for (size_t i = 0; i < count; ++i) {
160                         filters[i].init = get_function(ids[i]);
161                         if (filters[i].init == NULL)
162                                 return LZMA_HEADER_ERROR;
163
164                         filters[i].options = options[i].options;
165                         filters[i].uncompressed_size = uncompressed_sizes[i];
166                 }
167
168                 if (using_implicit)
169                         filters[count - 1].options = NULL;
170         }
171
172         // Terminate the array.
173         filters[count].init = NULL;
174
175         // Initialize the filters.
176         return lzma_next_filter_init(next, allocator, filters);
177 }