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 /* 230 extern LZMA_API(lzma_vli) 231 lzma_chunk_size(const lzma_filter *filters) 232 { 233 lzma_vli max = 0; 234 235 for (size_t i = 0; filters[i].id != LZMA_VLI_UNKNOWN; ++i) { 236 const lzma_filter_encoder *const fe 237 = encoder_find(filters[i].id); 238 if (fe->chunk_size != NULL) { 239 const lzma_vli size 240 = fe->chunk_size(filters[i].options); 241 if (size == LZMA_VLI_UNKNOWN) 242 return LZMA_VLI_UNKNOWN; 243 244 if (size > max) 245 max = size; 246 } 247 } 248 249 return max; 250 } 251 */ 252 253 254 extern LZMA_API(lzma_ret) 255 lzma_properties_size(uint32_t *size, const lzma_filter *filter) 256 { 257 const lzma_filter_encoder *const fe = encoder_find(filter->id); 258 if (fe == NULL) { 259 // Unknown filter - if the Filter ID is a proper VLI, 260 // return LZMA_OPTIONS_ERROR instead of LZMA_PROG_ERROR, 261 // because it's possible that we just don't have support 262 // compiled in for the requested filter. 263 return filter->id <= LZMA_VLI_MAX 264 ? LZMA_OPTIONS_ERROR : LZMA_PROG_ERROR; 265 } 266 267 if (fe->props_size_get == NULL) { 268 // No props_size_get() function, use props_size_fixed. 269 *size = fe->props_size_fixed; 270 return LZMA_OK; 271 } 272 273 return fe->props_size_get(size, filter->options); 274 } 275 276 277 extern LZMA_API(lzma_ret) 278 lzma_properties_encode(const lzma_filter *filter, uint8_t *props) 279 { 280 const lzma_filter_encoder *const fe = encoder_find(filter->id); 281 if (fe == NULL) 282 return LZMA_PROG_ERROR; 283 284 if (fe->props_encode == NULL) 285 return LZMA_OK; 286 287 return fe->props_encode(filter->options, props); 288 } 289