]> icculus.org git repositories - icculus/xz.git/blob - src/liblzma/common/raw_common.c
Added bsr.h.
[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 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 || !implicit || uncompressed_size[0]
66                                 != LZMA_VLI_VALUE_UNKNOWN)
67                         return false;
68
69                 // Add implicit Subblock filter.
70                 id[1] = LZMA_FILTER_SUBBLOCK;
71                 uncompressed_size[1] = LZMA_VLI_VALUE_UNKNOWN;
72                 id[2] = LZMA_VLI_VALUE_UNKNOWN;
73         }
74
75         return prepare(id + 1, uncompressed_size + 1, implicit);
76 }
77
78
79 extern lzma_ret
80 lzma_raw_coder_init(lzma_next_coder *next, lzma_allocator *allocator,
81                 const lzma_options_filter *options, lzma_vli uncompressed_size,
82                 lzma_init_function (*get_function)(lzma_vli id),
83                 bool allow_implicit, bool is_encoder)
84 {
85         if (options == NULL || !lzma_vli_is_valid(uncompressed_size))
86                 return LZMA_PROG_ERROR;
87
88         // Count the number of filters in the chain.
89         size_t count = 0;
90         while (options[count].id != LZMA_VLI_VALUE_UNKNOWN)
91                 ++count;
92
93         // Allocate enough space from the stack for IDs and uncompressed
94         // sizes. We need two extra: possible implicit Subblock and end
95         // of array indicator.
96         lzma_vli ids[count + 2];
97         lzma_vli uncompressed_sizes[count + 2];
98         bool using_implicit = false;
99
100         uncompressed_sizes[0] = uncompressed_size;
101
102         if (count == 0) {
103                 if (!allow_implicit)
104                         return LZMA_PROG_ERROR;
105
106                 count = 1;
107                 using_implicit = true;
108
109                 // Special case: no filters were specified, so an implicit
110                 // Copy or Subblock filter is used.
111                 if (uncompressed_size == LZMA_VLI_VALUE_UNKNOWN)
112                         ids[0] = LZMA_FILTER_SUBBLOCK;
113                 else
114                         ids[0] = LZMA_FILTER_COPY;
115
116                 ids[1] = LZMA_VLI_VALUE_UNKNOWN;
117
118         } else {
119                 // Prepare the ids[] and uncompressed_sizes[].
120                 for (size_t i = 0; i < count; ++i)
121                         ids[i] = options[i].id;
122
123                 ids[count] = LZMA_VLI_VALUE_UNKNOWN;
124
125                 if (prepare(ids, uncompressed_sizes, allow_implicit))
126                         return LZMA_HEADER_ERROR;
127
128                 // Check if implicit Subblock filter was added.
129                 if (ids[count] != LZMA_VLI_VALUE_UNKNOWN) {
130                         assert(ids[count] == LZMA_FILTER_SUBBLOCK);
131                         ++count;
132                         using_implicit = true;
133                 }
134         }
135
136         // Set the filter functions, and copy uncompressed sizes and options.
137         lzma_filter_info filters[count + 1];
138         if (is_encoder) {
139                 for (size_t i = 0; i < count; ++i) {
140                         // The order of the filters is reversed in the
141                         // encoder. It allows more efficient handling
142                         // of the uncompressed data.
143                         const size_t j = count - i - 1;
144
145                         filters[j].init = get_function(ids[i]);
146                         if (filters[j].init == NULL)
147                                 return LZMA_HEADER_ERROR;
148
149                         filters[j].options = options[i].options;
150                         filters[j].uncompressed_size = uncompressed_sizes[i];
151                 }
152
153                 if (using_implicit)
154                         filters[0].options = NULL;
155
156         } else {
157                 for (size_t i = 0; i < count; ++i) {
158                         filters[i].init = get_function(ids[i]);
159                         if (filters[i].init == NULL)
160                                 return LZMA_HEADER_ERROR;
161
162                         filters[i].options = options[i].options;
163                         filters[i].uncompressed_size = uncompressed_sizes[i];
164                 }
165
166                 if (using_implicit)
167                         filters[count - 1].options = NULL;
168         }
169
170         // Terminate the array.
171         filters[count].init = NULL;
172
173         // Initialize the filters.
174         return lzma_next_filter_init(next, allocator, filters);
175 }