OLD | NEW |
(Empty) | |
| 1 /////////////////////////////////////////////////////////////////////////////// |
| 2 // |
| 3 /// \file filter_decoder.c |
| 4 /// \brief Filter ID mapping to filter-specific functions |
| 5 // |
| 6 // Author: Lasse Collin |
| 7 // |
| 8 // This file has been put into the public domain. |
| 9 // You can do whatever you want with this file. |
| 10 // |
| 11 /////////////////////////////////////////////////////////////////////////////// |
| 12 |
| 13 #include "filter_encoder.h" |
| 14 #include "filter_common.h" |
| 15 #include "lzma_encoder.h" |
| 16 #include "lzma2_encoder.h" |
| 17 #include "simple_encoder.h" |
| 18 #include "delta_encoder.h" |
| 19 |
| 20 |
| 21 typedef struct { |
| 22 /// Filter ID |
| 23 lzma_vli id; |
| 24 |
| 25 /// Initializes the filter encoder and calls lzma_next_filter_init() |
| 26 /// for filters + 1. |
| 27 lzma_init_function init; |
| 28 |
| 29 /// Calculates memory usage of the encoder. If the options are |
| 30 /// invalid, UINT64_MAX is returned. |
| 31 uint64_t (*memusage)(const void *options); |
| 32 |
| 33 /// Calculates the minimum sane size for Blocks (or other types of |
| 34 /// chunks) to which the input data can be split to make |
| 35 /// multithreaded encoding possible. If this is NULL, it is assumed |
| 36 /// that the encoder is fast enough with single thread. |
| 37 lzma_vli (*chunk_size)(const void *options); |
| 38 |
| 39 /// Tells the size of the Filter Properties field. If options are |
| 40 /// invalid, UINT32_MAX is returned. If this is NULL, props_size_fixed |
| 41 /// is used. |
| 42 lzma_ret (*props_size_get)(uint32_t *size, const void *options); |
| 43 uint32_t props_size_fixed; |
| 44 |
| 45 /// Encodes Filter Properties. |
| 46 /// |
| 47 /// \return - LZMA_OK: Properties encoded successfully. |
| 48 /// - LZMA_OPTIONS_ERROR: Unsupported options |
| 49 /// - LZMA_PROG_ERROR: Invalid options or not enough |
| 50 /// output space |
| 51 lzma_ret (*props_encode)(const void *options, uint8_t *out); |
| 52 |
| 53 } lzma_filter_encoder; |
| 54 |
| 55 |
| 56 static const lzma_filter_encoder encoders[] = { |
| 57 #ifdef HAVE_ENCODER_LZMA1 |
| 58 { |
| 59 .id = LZMA_FILTER_LZMA1, |
| 60 .init = &lzma_lzma_encoder_init, |
| 61 .memusage = &lzma_lzma_encoder_memusage, |
| 62 .chunk_size = NULL, // FIXME |
| 63 .props_size_get = NULL, |
| 64 .props_size_fixed = 5, |
| 65 .props_encode = &lzma_lzma_props_encode, |
| 66 }, |
| 67 #endif |
| 68 #ifdef HAVE_ENCODER_LZMA2 |
| 69 { |
| 70 .id = LZMA_FILTER_LZMA2, |
| 71 .init = &lzma_lzma2_encoder_init, |
| 72 .memusage = &lzma_lzma2_encoder_memusage, |
| 73 .chunk_size = NULL, // FIXME |
| 74 .props_size_get = NULL, |
| 75 .props_size_fixed = 1, |
| 76 .props_encode = &lzma_lzma2_props_encode, |
| 77 }, |
| 78 #endif |
| 79 #ifdef HAVE_ENCODER_X86 |
| 80 { |
| 81 .id = LZMA_FILTER_X86, |
| 82 .init = &lzma_simple_x86_encoder_init, |
| 83 .memusage = NULL, |
| 84 .chunk_size = NULL, |
| 85 .props_size_get = &lzma_simple_props_size, |
| 86 .props_encode = &lzma_simple_props_encode, |
| 87 }, |
| 88 #endif |
| 89 #ifdef HAVE_ENCODER_POWERPC |
| 90 { |
| 91 .id = LZMA_FILTER_POWERPC, |
| 92 .init = &lzma_simple_powerpc_encoder_init, |
| 93 .memusage = NULL, |
| 94 .chunk_size = NULL, |
| 95 .props_size_get = &lzma_simple_props_size, |
| 96 .props_encode = &lzma_simple_props_encode, |
| 97 }, |
| 98 #endif |
| 99 #ifdef HAVE_ENCODER_IA64 |
| 100 { |
| 101 .id = LZMA_FILTER_IA64, |
| 102 .init = &lzma_simple_ia64_encoder_init, |
| 103 .memusage = NULL, |
| 104 .chunk_size = NULL, |
| 105 .props_size_get = &lzma_simple_props_size, |
| 106 .props_encode = &lzma_simple_props_encode, |
| 107 }, |
| 108 #endif |
| 109 #ifdef HAVE_ENCODER_ARM |
| 110 { |
| 111 .id = LZMA_FILTER_ARM, |
| 112 .init = &lzma_simple_arm_encoder_init, |
| 113 .memusage = NULL, |
| 114 .chunk_size = NULL, |
| 115 .props_size_get = &lzma_simple_props_size, |
| 116 .props_encode = &lzma_simple_props_encode, |
| 117 }, |
| 118 #endif |
| 119 #ifdef HAVE_ENCODER_ARMTHUMB |
| 120 { |
| 121 .id = LZMA_FILTER_ARMTHUMB, |
| 122 .init = &lzma_simple_armthumb_encoder_init, |
| 123 .memusage = NULL, |
| 124 .chunk_size = NULL, |
| 125 .props_size_get = &lzma_simple_props_size, |
| 126 .props_encode = &lzma_simple_props_encode, |
| 127 }, |
| 128 #endif |
| 129 #ifdef HAVE_ENCODER_SPARC |
| 130 { |
| 131 .id = LZMA_FILTER_SPARC, |
| 132 .init = &lzma_simple_sparc_encoder_init, |
| 133 .memusage = NULL, |
| 134 .chunk_size = NULL, |
| 135 .props_size_get = &lzma_simple_props_size, |
| 136 .props_encode = &lzma_simple_props_encode, |
| 137 }, |
| 138 #endif |
| 139 #ifdef HAVE_ENCODER_DELTA |
| 140 { |
| 141 .id = LZMA_FILTER_DELTA, |
| 142 .init = &lzma_delta_encoder_init, |
| 143 .memusage = &lzma_delta_coder_memusage, |
| 144 .chunk_size = NULL, |
| 145 .props_size_get = NULL, |
| 146 .props_size_fixed = 1, |
| 147 .props_encode = &lzma_delta_props_encode, |
| 148 }, |
| 149 #endif |
| 150 }; |
| 151 |
| 152 |
| 153 static const lzma_filter_encoder * |
| 154 encoder_find(lzma_vli id) |
| 155 { |
| 156 for (size_t i = 0; i < ARRAY_SIZE(encoders); ++i) |
| 157 if (encoders[i].id == id) |
| 158 return encoders + i; |
| 159 |
| 160 return NULL; |
| 161 } |
| 162 |
| 163 |
| 164 extern LZMA_API(lzma_bool) |
| 165 lzma_filter_encoder_is_supported(lzma_vli id) |
| 166 { |
| 167 return encoder_find(id) != NULL; |
| 168 } |
| 169 |
| 170 |
| 171 extern LZMA_API(lzma_ret) |
| 172 lzma_filters_update(lzma_stream *strm, const lzma_filter *filters) |
| 173 { |
| 174 if (strm->internal->next.update == NULL) |
| 175 return LZMA_PROG_ERROR; |
| 176 |
| 177 // Validate the filter chain. |
| 178 if (lzma_raw_encoder_memusage(filters) == UINT64_MAX) |
| 179 return LZMA_OPTIONS_ERROR; |
| 180 |
| 181 // The actual filter chain in the encoder is reversed. Some things |
| 182 // still want the normal order chain, so we provide both. |
| 183 size_t count = 1; |
| 184 while (filters[count].id != LZMA_VLI_UNKNOWN) |
| 185 ++count; |
| 186 |
| 187 lzma_filter reversed_filters[LZMA_FILTERS_MAX + 1]; |
| 188 for (size_t i = 0; i < count; ++i) |
| 189 reversed_filters[count - i - 1] = filters[i]; |
| 190 |
| 191 reversed_filters[count].id = LZMA_VLI_UNKNOWN; |
| 192 |
| 193 return strm->internal->next.update(strm->internal->next.coder, |
| 194 strm->allocator, filters, reversed_filters); |
| 195 } |
| 196 |
| 197 |
| 198 extern lzma_ret |
| 199 lzma_raw_encoder_init(lzma_next_coder *next, lzma_allocator *allocator, |
| 200 const lzma_filter *options) |
| 201 { |
| 202 return lzma_raw_coder_init(next, allocator, |
| 203 options, (lzma_filter_find)(&encoder_find), true); |
| 204 } |
| 205 |
| 206 |
| 207 extern LZMA_API(lzma_ret) |
| 208 lzma_raw_encoder(lzma_stream *strm, const lzma_filter *options) |
| 209 { |
| 210 lzma_next_strm_init(lzma_raw_coder_init, strm, options, |
| 211 (lzma_filter_find)(&encoder_find), true); |
| 212 |
| 213 strm->internal->supported_actions[LZMA_RUN] = true; |
| 214 strm->internal->supported_actions[LZMA_SYNC_FLUSH] = true; |
| 215 strm->internal->supported_actions[LZMA_FINISH] = true; |
| 216 |
| 217 return LZMA_OK; |
| 218 } |
| 219 |
| 220 |
| 221 extern LZMA_API(uint64_t) |
| 222 lzma_raw_encoder_memusage(const lzma_filter *filters) |
| 223 { |
| 224 return lzma_raw_coder_memusage( |
| 225 (lzma_filter_find)(&encoder_find), filters); |
| 226 } |
| 227 |
| 228 |
| 229 extern LZMA_API(lzma_vli) |
| 230 lzma_chunk_size(const lzma_filter *filters) |
| 231 { |
| 232 lzma_vli max = 0; |
| 233 |
| 234 for (size_t i = 0; filters[i].id != LZMA_VLI_UNKNOWN; ++i) { |
| 235 const lzma_filter_encoder *const fe |
| 236 = encoder_find(filters[i].id); |
| 237 if (fe->chunk_size != NULL) { |
| 238 const lzma_vli size |
| 239 = fe->chunk_size(filters[i].options); |
| 240 if (size == LZMA_VLI_UNKNOWN) |
| 241 return LZMA_VLI_UNKNOWN; |
| 242 |
| 243 if (size > max) |
| 244 max = size; |
| 245 } |
| 246 } |
| 247 |
| 248 return max; |
| 249 } |
| 250 |
| 251 |
| 252 extern LZMA_API(lzma_ret) |
| 253 lzma_properties_size(uint32_t *size, const lzma_filter *filter) |
| 254 { |
| 255 const lzma_filter_encoder *const fe = encoder_find(filter->id); |
| 256 if (fe == NULL) { |
| 257 // Unknown filter - if the Filter ID is a proper VLI, |
| 258 // return LZMA_OPTIONS_ERROR instead of LZMA_PROG_ERROR, |
| 259 // because it's possible that we just don't have support |
| 260 // compiled in for the requested filter. |
| 261 return filter->id <= LZMA_VLI_MAX |
| 262 ? LZMA_OPTIONS_ERROR : LZMA_PROG_ERROR; |
| 263 } |
| 264 |
| 265 if (fe->props_size_get == NULL) { |
| 266 // No props_size_get() function, use props_size_fixed. |
| 267 *size = fe->props_size_fixed; |
| 268 return LZMA_OK; |
| 269 } |
| 270 |
| 271 return fe->props_size_get(size, filter->options); |
| 272 } |
| 273 |
| 274 |
| 275 extern LZMA_API(lzma_ret) |
| 276 lzma_properties_encode(const lzma_filter *filter, uint8_t *props) |
| 277 { |
| 278 const lzma_filter_encoder *const fe = encoder_find(filter->id); |
| 279 if (fe == NULL) |
| 280 return LZMA_PROG_ERROR; |
| 281 |
| 282 if (fe->props_encode == NULL) |
| 283 return LZMA_OK; |
| 284 |
| 285 return fe->props_encode(filter->options, props); |
| 286 } |
OLD | NEW |