]> icculus.org git repositories - icculus/xz.git/blob - src/liblzma/common/raw_common.c
Update the code to mostly match the new simpler file format
[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 static lzma_ret
24 validate_options(const lzma_options_filter *options, size_t *count)
25 {
26         if (options == NULL)
27                 return LZMA_PROG_ERROR;
28
29         // Number of non-last filters that may change the size of the data
30         // significantly (that is, more than 1-2 % or so).
31         size_t change = 0;
32
33         // True if the last filter in the given chain is actually usable as
34         // the last filter. Only filters that support embedding End of Payload
35         // Marker can be used as the last filter in the chain.
36         bool last_ok = false;
37
38         size_t i;
39         for (i = 0; options[i].id != LZMA_VLI_VALUE_UNKNOWN; ++i) {
40                 switch (options[i].id) {
41                 // Not #ifdeffing these for simplicity.
42                 case LZMA_FILTER_X86:
43                 case LZMA_FILTER_POWERPC:
44                 case LZMA_FILTER_IA64:
45                 case LZMA_FILTER_ARM:
46                 case LZMA_FILTER_ARMTHUMB:
47                 case LZMA_FILTER_SPARC:
48                 case LZMA_FILTER_DELTA:
49                         // These don't change the size of the data and cannot
50                         // be used as the last filter in the chain.
51                         last_ok = false;
52                         break;
53
54 #ifdef HAVE_FILTER_SUBBLOCK
55                 case LZMA_FILTER_SUBBLOCK:
56                         last_ok = true;
57                         ++change;
58                         break;
59 #endif
60
61 #ifdef HAVE_FILTER_LZMA
62                 case LZMA_FILTER_LZMA:
63                         last_ok = true;
64                         break;
65 #endif
66
67                 default:
68                         return LZMA_HEADER_ERROR;
69                 }
70         }
71
72         // There must be 1-4 filters and the last filter must be usable as
73         // the last filter in the chain.
74         if (i == 0 || i > 4 || !last_ok)
75                 return LZMA_HEADER_ERROR;
76
77         // At maximum of two non-last filters are allowed to change the
78         // size of the data.
79         if (change > 2)
80                 return LZMA_HEADER_ERROR;
81
82         *count = i;
83         return LZMA_OK;
84 }
85
86
87 extern lzma_ret
88 lzma_raw_coder_init(lzma_next_coder *next, lzma_allocator *allocator,
89                 const lzma_options_filter *options,
90                 lzma_init_function (*get_function)(lzma_vli id),
91                 bool is_encoder)
92 {
93         // Do some basic validation and get the number of filters.
94         size_t count;
95         return_if_error(validate_options(options, &count));
96
97         // Set the filter functions and copy the options pointer.
98         lzma_filter_info filters[count + 1];
99         if (is_encoder) {
100                 for (size_t i = 0; i < count; ++i) {
101                         // The order of the filters is reversed in the
102                         // encoder. It allows more efficient handling
103                         // of the uncompressed data.
104                         const size_t j = count - i - 1;
105
106                         filters[j].init = get_function(options[i].id);
107                         if (filters[j].init == NULL)
108                                 return LZMA_HEADER_ERROR;
109
110                         filters[j].options = options[i].options;
111                 }
112         } else {
113                 for (size_t i = 0; i < count; ++i) {
114                         filters[i].init = get_function(options[i].id);
115                         if (filters[i].init == NULL)
116                                 return LZMA_HEADER_ERROR;
117
118                         filters[i].options = options[i].options;
119                 }
120         }
121
122         // Terminate the array.
123         filters[count].init = NULL;
124
125         // Initialize the filters.
126         return lzma_next_filter_init(next, allocator, filters);
127 }