filter_encoder.c revision 292588
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 21typedef 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 recommended Uncompressed Size for .xz Blocks to 34 /// which the input data can be split to make multithreaded 35 /// encoding possible. If this is NULL, it is assumed that 36 /// the encoder is fast enough with single thread. 37 uint64_t (*block_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 56static 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 .block_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 .block_size = &lzma_lzma2_block_size, // 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 .block_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 .block_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 .block_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 .block_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 .block_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 .block_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 .block_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 153static const lzma_filter_encoder * 154encoder_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 164extern LZMA_API(lzma_bool) 165lzma_filter_encoder_is_supported(lzma_vli id) 166{ 167 return encoder_find(id) != NULL; 168} 169 170 171extern LZMA_API(lzma_ret) 172lzma_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 198extern lzma_ret 199lzma_raw_encoder_init(lzma_next_coder *next, const 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 207extern LZMA_API(lzma_ret) 208lzma_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 221extern LZMA_API(uint64_t) 222lzma_raw_encoder_memusage(const lzma_filter *filters) 223{ 224 return lzma_raw_coder_memusage( 225 (lzma_filter_find)(&encoder_find), filters); 226} 227 228 229extern uint64_t 230lzma_mt_block_size(const lzma_filter *filters) 231{ 232 uint64_t 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->block_size != NULL) { 238 const uint64_t size 239 = fe->block_size(filters[i].options); 240 if (size == 0) 241 return 0; 242 243 if (size > max) 244 max = size; 245 } 246 } 247 248 return max; 249} 250 251 252extern LZMA_API(lzma_ret) 253lzma_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 275extern LZMA_API(lzma_ret) 276lzma_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} 287