]> icculus.org git repositories - icculus/xz.git/blob - src/liblzma/common/raw_encoder.c
Do uncompressed size validation in raw encoder. This way
[icculus/xz.git] / src / liblzma / common / raw_encoder.c
1 ///////////////////////////////////////////////////////////////////////////////
2 //
3 /// \file       raw_encoder.c
4 /// \brief      Raw encoder initialization API
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_encoder.h"
21 #include "copy_coder.h"
22 #include "simple_coder.h"
23 #include "subblock_encoder.h"
24 #include "delta_encoder.h"
25 #include "lzma_encoder.h"
26
27
28 struct lzma_coder_s {
29         lzma_next_coder next;
30         lzma_vli uncompressed_size;
31 };
32
33
34 static lzma_init_function
35 get_function(lzma_vli id)
36 {
37         switch (id) {
38 #ifdef HAVE_FILTER_COPY
39         case LZMA_FILTER_COPY:
40                 return &lzma_copy_encoder_init;
41 #endif
42
43 #ifdef HAVE_FILTER_SUBBLOCK
44         case LZMA_FILTER_SUBBLOCK:
45                 return &lzma_subblock_encoder_init;
46 #endif
47
48 #ifdef HAVE_FILTER_X86
49         case LZMA_FILTER_X86:
50                 return &lzma_simple_x86_encoder_init;
51 #endif
52
53 #ifdef HAVE_FILTER_POWERPC
54         case LZMA_FILTER_POWERPC:
55                 return &lzma_simple_powerpc_encoder_init;
56 #endif
57
58 #ifdef HAVE_FILTER_IA64
59         case LZMA_FILTER_IA64:
60                 return &lzma_simple_ia64_encoder_init;
61 #endif
62
63 #ifdef HAVE_FILTER_ARM
64         case LZMA_FILTER_ARM:
65                 return &lzma_simple_arm_encoder_init;
66 #endif
67
68 #ifdef HAVE_FILTER_ARMTHUMB
69         case LZMA_FILTER_ARMTHUMB:
70                 return &lzma_simple_armthumb_encoder_init;
71 #endif
72
73 #ifdef HAVE_FILTER_SPARC
74         case LZMA_FILTER_SPARC:
75                 return &lzma_simple_sparc_encoder_init;
76 #endif
77
78 #ifdef HAVE_FILTER_DELTA
79         case LZMA_FILTER_DELTA:
80                 return &lzma_delta_encoder_init;
81 #endif
82
83 #ifdef HAVE_FILTER_LZMA
84         case LZMA_FILTER_LZMA:
85                 return &lzma_lzma_encoder_init;
86 #endif
87         }
88
89         return NULL;
90 }
91
92
93 static lzma_ret
94 raw_encode(lzma_coder *coder, lzma_allocator *allocator,
95                 const uint8_t *restrict in, size_t *restrict in_pos,
96                 size_t in_size, uint8_t *restrict out,
97                 size_t *restrict out_pos, size_t out_size, lzma_action action)
98 {
99         // Check that our amount of input stays in proper limits.
100         if (coder->uncompressed_size != LZMA_VLI_VALUE_UNKNOWN) {
101                 if (action == LZMA_FINISH) {
102                         if (coder->uncompressed_size != in_size - *in_pos)
103                                 return LZMA_PROG_ERROR;
104                 } else {
105                         if (coder->uncompressed_size < in_size - *in_pos)
106                                 return LZMA_PROG_ERROR;
107                 }
108         }
109
110         const size_t in_start = *in_pos;
111
112         const lzma_ret ret = coder->next.code(coder->next.coder, allocator,
113                         in, in_pos, in_size, out, out_pos, out_size, action);
114
115         if (coder->uncompressed_size != LZMA_VLI_VALUE_UNKNOWN)
116                 coder->uncompressed_size -= *in_pos - in_start;
117
118         return ret;
119 }
120
121
122 static void
123 raw_encoder_end(lzma_coder *coder, lzma_allocator *allocator)
124 {
125         lzma_next_coder_end(&coder->next, allocator);
126         lzma_free(coder, allocator);
127         return;
128 }
129
130
131 static lzma_ret
132 raw_encoder_init(lzma_next_coder *next, lzma_allocator *allocator,
133                 const lzma_options_filter *options,
134                 lzma_vli uncompressed_size, bool allow_implicit)
135 {
136         if (next->coder == NULL) {
137                 next->coder = lzma_alloc(sizeof(lzma_coder), allocator);
138                 if (next->coder == NULL)
139                         return LZMA_MEM_ERROR;
140
141                 next->code = &raw_encode;
142                 next->end = &raw_encoder_end;
143
144                 next->coder->next = LZMA_NEXT_CODER_INIT;
145         }
146
147         next->coder->uncompressed_size = uncompressed_size;
148
149         // lzma_raw_coder_init() accesses get_function() via function pointer,
150         // because this way linker doesn't statically link both encoder and
151         // decoder functions if user needs only encoder or decoder.
152         return lzma_raw_coder_init(&next->coder->next, allocator,
153                         options, uncompressed_size,
154                         &get_function, allow_implicit, true);
155 }
156
157
158 extern lzma_ret
159 lzma_raw_encoder_init(lzma_next_coder *next, lzma_allocator *allocator,
160                 const lzma_options_filter *options,
161                 lzma_vli uncompressed_size, bool allow_implicit)
162 {
163         lzma_next_coder_init(raw_encoder_init, next, allocator,
164                         options, uncompressed_size, allow_implicit);
165 }
166
167
168 extern LZMA_API lzma_ret
169 lzma_raw_encoder(lzma_stream *strm, const lzma_options_filter *options,
170                 lzma_vli uncompressed_size, lzma_bool allow_implicit)
171 {
172         lzma_next_strm_init(strm, raw_encoder_init,
173                         options, uncompressed_size, allow_implicit);
174
175         strm->internal->supported_actions[LZMA_RUN] = true;
176         strm->internal->supported_actions[LZMA_SYNC_FLUSH] = true;
177         strm->internal->supported_actions[LZMA_FINISH] = true;
178
179         return LZMA_OK;
180 }