diff --git a/lib/decmp.c b/lib/decmp.c
index c22e5e4a2b4860d4294097a5db2dce73b3043122..3c7acfb5cf1eee14b5b2e7037a50a5191987ab44 100644
--- a/lib/decmp.c
+++ b/lib/decmp.c
@@ -1,3 +1,24 @@
+/**
+ * @file   decmp.c
+ * @author Dominik Loidolt (dominik.loidolt@univie.ac.at),
+ * @date   2020
+ *
+ * @copyright GPLv2
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * @brief software decompression library
+ * @see Data Compression User Manual PLATO-UVIE-PL-UM-0001
+ *
+ * TODO: how to decomprss?
+ */
+
 #include <stdint.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -10,19 +31,21 @@
 #include "cmp_data_types.h"
 #include "cmp_entity.h"
 
-#define CMP_ERROR_SAMLL_BUF -2
 
+/* maximum used bits registry */
+extern struct cmp_max_used_bits max_used_bits;
+
+/* function pointer to a code word decoder function */
+typedef int (*decoder_ptr)(unsigned int, unsigned int, unsigned int, unsigned int *);
 
 /* structure to hold a setup to encode a value */
-typedef unsigned int (*decoder_ptr)(unsigned int, unsigned int, unsigned int, unsigned int *);
 struct decoder_setup {
-	/* generate_cw_f_pt generate_cw_f; /1* pointer to the code word generation function *1/ */
-	decoder_ptr decode_cw_f;
-	int (*encode_method_f)(uint32_t *decoded_value, int stream_pos,
+	decoder_ptr decode_cw_f; /* pointer to the code word decoder (Golomb/Rice)*/
+	int (*decode_method_f)(uint32_t *decoded_value, int stream_pos,
 			       const struct decoder_setup *setup); /* pointer to the decoding function */
 	uint32_t *bitstream_adr; /* start address of the compressed data bitstream */
 	uint32_t max_stream_len; /* maximum length of the bitstream/icu_output_buf in bits */
-	uint32_t max_cw_len;
+	uint32_t max_cw_len; /* TODO */
 	uint32_t encoder_par1; /* encoding parameter 1 */
 	uint32_t encoder_par2; /* encoding parameter 2 */
 	uint32_t outlier_par; /* outlier parameter */
@@ -32,23 +55,22 @@ struct decoder_setup {
 };
 
 
-double get_compression_ratio(uint32_t samples, uint32_t cmp_size_bits,
-			     enum cmp_data_type data_type)
-{
-	double orign_len_bits = (double)cmp_cal_size_of_data(samples, data_type) * CHAR_BIT;
-
-	return orign_len_bits/(double)cmp_size_bits;
-}
-
+/**
+ * @brief count leading 1-bits
+ *
+ * @param value	input vale
+ *
+ * @returns the number of leading 1-bits in value, starting at the most
+ *	significant bit position
+ */
 
-static unsigned int count_leading_ones(unsigned int value)
+static unsigned int count_leading_ones(uint32_t value)
 {
 	unsigned int n_ones = 0; /* number of leading 1s */
 
 	while (1) {
-		unsigned int leading_bit;
+		uint32_t leading_bit = value & 0x80000000;
 
-		leading_bit = value & 0x80000000;
 		if (!leading_bit)
 			break;
 
@@ -59,7 +81,19 @@ static unsigned int count_leading_ones(unsigned int value)
 }
 
 
-static unsigned int rice_decoder(uint32_t code_word, unsigned int m,
+/**
+ * @brief decode a Rice code word
+ *
+ * @param code_word	Rice code word bitstream starting at the MSB
+ * @param m		Golomb parameter (not used)
+ * @param log2_m	Rice parameter, must be the same used for encoding
+ * @param decoded_cw	pointer where decoded value is written
+ *
+ * @returns the length of the decoded code word in bits (NOT the decoded value);
+ *	0 on failure
+ */
+
+static int rice_decoder(uint32_t code_word, unsigned int m,
 				 unsigned int log2_m, unsigned int *decoded_cw)
 {
 	unsigned int q; /* quotient code */
@@ -68,9 +102,9 @@ static unsigned int rice_decoder(uint32_t code_word, unsigned int m,
 	unsigned int rl; /* length of the remainder code */
 	unsigned int cw_len; /* length of the decoded code word in bits */
 
-	(void)m;
+	(void)m; /* we don't need the Golomb parameter */
 
-	q = count_leading_ones(code_word);
+	q = count_leading_ones(code_word); /* decode unary coding */
 	ql = q + 1; /* Number of 1's + following 0 */
 
 	rl = log2_m;
@@ -96,7 +130,20 @@ static unsigned int rice_decoder(uint32_t code_word, unsigned int m,
 }
 
 
-static unsigned int golomb_decoder(unsigned int code_word, unsigned int m,
+/**
+ * @brief decode a Golomb code word
+ *
+ * @param code_word	Golomb code word bitstream starting at the MSB
+ * @param m		Golomb parameter (have to be bigger than 0)
+ * @param log2_m	is log_2(m) calculate outside function for better
+ *			performance
+ * @param decoded_cw	pointer where decoded value is written
+ *
+ * @returns the length of the decoded code word in bits (NOT the decoded value);
+ *	0 on failure
+ */
+
+static int golomb_decoder(unsigned int code_word, unsigned int m,
 				   unsigned int log2_m, unsigned int
 				   *decoded_cw)
 {
@@ -108,7 +155,7 @@ static unsigned int golomb_decoder(unsigned int code_word, unsigned int m,
 	unsigned int cutoff; /* cutoff between group 1 and 2 */
 	unsigned int cw_len; /* length of the decoded code word in bits */
 
-	q = count_leading_ones(code_word);
+	q = count_leading_ones(code_word); /* decode unary coding */
 
 	rl = log2_m + 1;
 	code_word <<= (q+1);  /* shift quotient code out */
@@ -118,10 +165,10 @@ static unsigned int golomb_decoder(unsigned int code_word, unsigned int m,
 
 	cutoff = (1UL << rl) - m;
 
-	if (r1 < cutoff) {
+	if (r1 < cutoff) { /* group 1 */
 		cw_len = q + rl;
 		r = r1;
-	} else {
+	} else { /* group 2 */
 		cw_len = q + rl + 1;
 		r = r2 - cutoff;
 	}
@@ -134,6 +181,16 @@ static unsigned int golomb_decoder(unsigned int code_word, unsigned int m,
 }
 
 
+/**
+ * @brief select the decoder based on the used Golomb parameter
+ * @note if the Golomb parameter is a power of 2 we can use the faster Rice
+ *	decoder
+ *
+ * @param golomb_par	Golomb parameter (have to be bigger than 0)
+ *
+ * @returns function pointer to the select decoder function; NULL on failure
+ */
+
 static decoder_ptr select_decoder(unsigned int golomb_par)
 {
 	if (!golomb_par)
@@ -149,7 +206,9 @@ static decoder_ptr select_decoder(unsigned int golomb_par)
 /**
  * @brief read a value of up to 32 bits from a bitstream
  *
- * @param p_value		pointer to the read value
+ * @param p_value		pointer to the read value (can be NULL), the
+ *				read value will be converted to the system
+ *				endianness
  * @param n_bits		number of bits to read from the bitstream
  * @param bit_offset		bit index where the bits will be read, seen from
  *				the very beginning of the bitstream
@@ -158,9 +217,10 @@ static decoder_ptr select_decoder(unsigned int golomb_par)
  * @param max_stream_len	maximum length of the bitstream in bits; is
  *				ignored if bitstream_adr is NULL
  *
- * @returns length in bits of the generated bitstream on success; returns
- *          negative in case of erroneous input; returns CMP_ERROR_SAMLL_BUF if
- *          the bitstream buffer is too small to read the value from the bitstream
+ * @returns bit position of the last read bit in the bitstream on success;
+ *	returns negative in case of erroneous input; returns CMP_ERROR_SAMLL_BUF
+ *	if the bitstream buffer is too small to read the value from the
+ *	bitstream
  */
 
 static int get_n_bits32(uint32_t *p_value, unsigned int n_bits, int bit_offset,
@@ -174,16 +234,14 @@ static int get_n_bits32(uint32_t *p_value, unsigned int n_bits, int bit_offset,
 	/*leave in case of erroneous input */
 	if (bit_offset < 0)
 		return -1;
-
 	if (n_bits == 0)
-		return stream_len;
-
+		return -1;
 	if (n_bits > 32)
 		return -1;
 
+	/* nothing to read */
 	if (!bitstream_adr)
 		return stream_len;
-
 	if (!p_value)
 		return stream_len;
 
@@ -231,88 +289,130 @@ static int get_n_bits32(uint32_t *p_value, unsigned int n_bits, int bit_offset,
 }
 
 
-static int decode_normal(uint32_t *decoded_value, int stream_pos, const struct decoder_setup *setup)
-{
-	uint32_t read_val = ~0U;
-	int n_read_bits, cw_len, n_bits;
+/**
+ * @brief decode a Golomb/Rice encoded code word from the bitstream
+ *
+ * @param decoded_value	pointer to the decoded value
+ * @param stream_pos	start bit position code word to be decoded in the bitstream
+ * @param setup		pointer to the decoder setup
+ *
+ * @returns bit index of the next code word in the bitstream on success; returns
+ *	negative in case of erroneous input; returns CMP_ERROR_SAMLL_BUF if the
+ *	bitstream buffer is too small to read the value from the bitstream
+ */
 
-	if (stream_pos + setup->max_cw_len > setup->max_stream_len)   /* check buffer overflow */
-		n_read_bits = setup->max_stream_len - stream_pos;
+static int decode_normal(uint32_t *decoded_value, int stream_pos,
+			 const struct decoder_setup *setup)
+{
+	uint32_t read_val;
+	unsigned int n_read_bits;
+	int stream_pos_read, cw_len;
+
+	/* check if we can read max_cw_len or less; we do not now how long the
+	 * code word actually is so we try to read the maximum cw length */
+	if ((unsigned int)stream_pos + setup->max_cw_len > setup->max_stream_len)
+		n_read_bits = setup->max_stream_len - (unsigned int)stream_pos;
 	else
 		n_read_bits = setup->max_cw_len;
-	if (n_read_bits >= 32 || n_read_bits == 0)
-		return -1;
 
-	n_bits = get_n_bits32(&read_val, n_read_bits, stream_pos,
-				  setup->bitstream_adr, setup->max_stream_len);
-	if (n_bits <= 0)
-		return -1;
+	stream_pos_read = get_n_bits32(&read_val, n_read_bits, stream_pos,
+				       setup->bitstream_adr, setup->max_stream_len);
+	if (stream_pos_read < 0)
+		return stream_pos_read;
 
+	/* if we read less than 32, we shift the bitstream so that it starts at the MSB */
 	read_val = read_val << (32 - n_read_bits);
 
-	cw_len = setup->decode_cw_f(read_val, setup->encoder_par1, setup->encoder_par2, decoded_value);
-	if (cw_len < 0)
+	cw_len = setup->decode_cw_f(read_val, setup->encoder_par1,
+				    setup->encoder_par2, decoded_value);
+	if (cw_len <= 0)
+		return -1;
+	/* consistency check: code word length can not be bigger than read bits */
+	if (cw_len > (int)n_read_bits)
 		return -1;
 
 	return stream_pos + cw_len;
 }
 
 
-static int decode_multi(uint32_t *decoded_value, int stream_pos,
-			    const struct decoder_setup *setup)
+/**
+ * @brief decode a Golomb/Rice encoded code word with zero escape system
+ *	mechanism from the bitstream
+ *
+ * @param decoded_value	pointer to the decoded value
+ * @param stream_pos	start bit position code word to be decoded in the bitstream
+ * @param setup		pointer to the decoder setup
+ *
+ * @returns bit index of the next code word in the bitstream on success; returns
+ *	negative in case of erroneous input; returns CMP_ERROR_SAMLL_BUF if the
+ *	bitstream buffer is too small to read the value from the bitstream
+ */
+
+static int decode_zero(uint32_t *decoded_value, int stream_pos,
+		       const struct decoder_setup *setup)
 {
 	stream_pos = decode_normal(decoded_value, stream_pos, setup);
 	if (stream_pos < 0)
 		return stream_pos;
 
-	if (*decoded_value >= setup->outlier_par) {
-		/* escape symbol mechanism was used; read unencoded value */
-		int n_bits;
-		uint32_t unencoded_val = 0;
-		unsigned int unencoded_len;
+	/* consistency check: value lager than the outlier parameter should not
+	 * be Golomb/Rice encoded */
+	if (*decoded_value > setup->outlier_par)
+		return -1;
 
-		unencoded_len = (*decoded_value - setup->outlier_par + 1) * 2;
+	if (*decoded_value == 0) {
+		/* escape symbol mechanism was used; read unencoded value */
+		uint32_t unencoded_val;
 
-		n_bits = get_n_bits32(&unencoded_val, unencoded_len, stream_pos,
-				  setup->bitstream_adr, setup->max_stream_len);
-		if (n_bits <= 0)
+		stream_pos = get_n_bits32(&unencoded_val, setup->max_data_bits, stream_pos,
+					  setup->bitstream_adr, setup->max_stream_len);
+		if (stream_pos < 0)
+			return stream_pos;
+		/* consistency check: outliers must be bigger than the outlier_par */
+		if (unencoded_val < setup->outlier_par && unencoded_val != 0)
 			return -1;
 
-		*decoded_value = unencoded_val + setup->outlier_par;
-		stream_pos += unencoded_len;
+		*decoded_value = unencoded_val;
 	}
+
+	(*decoded_value)--;
+	if (*decoded_value == 0xFFFFFFFF) /* catch underflow */
+		(*decoded_value) >>=  (32 - setup->max_data_bits);
+
 	return stream_pos;
 }
 
 
-static int decode_zero(uint32_t *decoded_value, int stream_pos,
-			   const struct decoder_setup *setup)
+/**
+ * @brief decode a Golomb/Rice encoded code word with multi escape system
+ *	mechanism from the bitstream
+ *
+ * @param decoded_value	pointer to the decoded value
+ * @param stream_pos	start bit position code word to be decoded in the bitstream
+ * @param setup		pointer to the decoder setup
+ *
+ * @returns bit index of the next code word in the bitstream on success; returns
+ *	negative in case of erroneous input; returns CMP_ERROR_SAMLL_BUF if the
+ *	bitstream buffer is too small to read the value from the bitstream
+ */
+
+static int decode_multi(uint32_t *decoded_value, int stream_pos,
+			const struct decoder_setup *setup)
 {
 	stream_pos = decode_normal(decoded_value, stream_pos, setup);
 
-	if (stream_pos <= 0)
-		return stream_pos;
-
-	if (*decoded_value > setup->outlier_par) /* consistency check */
-		return -1;
+	if (*decoded_value >= setup->outlier_par) {
+		/* escape symbol mechanism was used; read unencoded value */
+		uint32_t unencoded_val;
+		unsigned int unencoded_len;
 
-	if (*decoded_value == 0) {/* escape symbol mechanism was used; read unencoded value */
-		int n_bits;
-		uint32_t unencoded_val = 0;
+		unencoded_len = (*decoded_value - setup->outlier_par + 1) * 2;
 
-		n_bits = get_n_bits32(&unencoded_val, setup->max_data_bits, stream_pos,
-				  setup->bitstream_adr, setup->max_stream_len);
-		if (n_bits <= 0)
-			return -1;
-		if (unencoded_val < setup->outlier_par && unencoded_val != 0) /* consistency check */
-			return -1;
+		stream_pos = get_n_bits32(&unencoded_val, unencoded_len, stream_pos,
+					  setup->bitstream_adr, setup->max_stream_len);
 
-		*decoded_value = unencoded_val;
-		stream_pos += setup->max_data_bits;
+		*decoded_value = unencoded_val + setup->outlier_par;
 	}
-	(*decoded_value)--;
-	if (*decoded_value == 0xFFFFFFFF) /* catch underflow */
-		(*decoded_value) = (*decoded_value) >> (32-setup->max_data_bits);
 	return stream_pos;
 }
 
@@ -332,21 +432,36 @@ static uint32_t re_map_to_pos(uint32_t value_to_unmap)
 		if (value_to_unmap == 0xFFFFFFFF) /* catch overflow */
 			return 0x80000000;
 		return -((value_to_unmap + 1) / 2);
-	} else
+	} else {
 		return value_to_unmap / 2;
+	}
 }
 
 
+/**
+ * @brief decompress the next code word in the bitstream and decorate it with
+ *	the model
+ *
+ * @param decoded_value	pointer to the decoded value
+ * @param model		model of the decoded_value (0 if not used)
+ * @param stream_pos	start bit position code word to be decoded in the bitstream
+ * @param setup		pointer to the decoder setup
+ *
+ * @returns bit index of the next code word in the bitstream on success; returns
+ *	negative in case of erroneous input; returns CMP_ERROR_SAMLL_BUF if the
+ *	bitstream buffer is too small to read the value from the bitstream
+ */
+
 static int decode_value(uint32_t *decoded_value, uint32_t model,
 			int stream_pos, const struct decoder_setup *setup)
 {
 	uint32_t mask = (~0U >> (32 - setup->max_data_bits)); /* mask the used bits */
 
-	stream_pos = setup->encode_method_f(decoded_value, stream_pos, setup);
+	stream_pos = setup->decode_method_f(decoded_value, stream_pos, setup);
 	if (stream_pos <= 0)
 		return stream_pos;
 
-	*decoded_value = re_map_to_pos(*decoded_value); //, setup->max_used_bits);
+	*decoded_value = re_map_to_pos(*decoded_value);
 
 	*decoded_value += round_fwd(model, setup->lossy_par);
 
@@ -364,9 +479,9 @@ static int configure_decoder_setup(struct decoder_setup *setup,
 				   const struct cmp_cfg *cfg)
 {
 	if (multi_escape_mech_is_used(cfg->cmp_mode))
-		setup->encode_method_f = &decode_multi;
+		setup->decode_method_f = &decode_multi;
 	else if (zero_escape_mech_is_used(cfg->cmp_mode))
-		setup->encode_method_f = &decode_zero;
+		setup->decode_method_f = &decode_zero;
 	else {
 		debug_print("Error: Compression mode not supported.\n");
 		return -1;
@@ -396,6 +511,7 @@ static int configure_decoder_setup(struct decoder_setup *setup,
 
 static int decompress_imagette(struct cmp_cfg *cfg)
 {
+	int err;
 	size_t i;
 	int stream_pos = 0;
 	struct decoder_setup setup;
@@ -404,10 +520,9 @@ static int decompress_imagette(struct cmp_cfg *cfg)
 	uint16_t *up_model_buf = cfg->icu_new_model_buf;
 	uint32_t decoded_value = 0;
 	uint16_t model;
-	int err;
 
 	err = configure_decoder_setup(&setup, cfg->golomb_par, cfg->spill,
-				      cfg->round, 16, cfg);
+				      cfg->round, max_used_bits.nc_imagette, cfg);
 	if (err)
 		return -1;
 
@@ -432,118 +547,1588 @@ static int decompress_imagette(struct cmp_cfg *cfg)
 	return stream_pos;
 }
 
-static int decompressed_data_internal(struct cmp_cfg *cfg)
-{
-	int data_size, strem_len_bit = -1;
 
-	if (!cfg)
-		return 0; /* or -1? */
-	if (!cfg->icu_output_buf)
+/**
+ * @brief TODO: decompress the multi-entry packet header structure and sets the data,
+ *	model and up_model pointers to the data after the header
+ *
+ * @param data		pointer to a pointer pointing to the data to be compressed
+ * @param model		pointer to a pointer pointing to the model of the data
+ * @param up_model	pointer to a pointer pointing to the updated model buffer
+ * @param cfg		pointer to the compression configuration structure
+ *
+ * @returns the bit length of the bitstream on success; negative on error,
+ *
+ * @note the (void **) cast relies on all pointer types having the same internal
+ *	representation which is common, but not universal; http://www.c-faq.com/ptrs/genericpp.html
+ */
+
+static int decompress_multi_entry_hdr(void **data, void **model, void **up_model,
+				      const struct cmp_cfg *cfg)
+{
+	if (cfg->buffer_length < MULTI_ENTRY_HDR_SIZE)
 		return -1;
 
-	data_size = cmp_cal_size_of_data(cfg->samples, cfg->data_type);
-	if (!cfg->input_buf || !data_size)
-		return data_size;
+	if (*data) {
+		if (cfg->icu_output_buf)
+			memcpy(*data, cfg->icu_output_buf, MULTI_ENTRY_HDR_SIZE);
+		*data = (uint8_t *)*data + MULTI_ENTRY_HDR_SIZE;
+	}
 
-	if (model_mode_is_used(cfg->cmp_mode))
-		if (!cfg->model_buf)
-			return -1;
+	if (*model) {
+		if (cfg->icu_output_buf)
+			memcpy(*model, cfg->icu_output_buf, MULTI_ENTRY_HDR_SIZE);
+		*model = (uint8_t *)*model + MULTI_ENTRY_HDR_SIZE;
+	}
 
-	if (cfg->cmp_mode == CMP_MODE_RAW) {
+	if (*up_model) {
+		if (cfg->icu_output_buf)
+			memcpy(*up_model, cfg->icu_output_buf, MULTI_ENTRY_HDR_SIZE);
+		*up_model = (uint8_t *)*up_model + MULTI_ENTRY_HDR_SIZE;
+	}
 
-		if ((unsigned int)data_size < cfg->buffer_length/CHAR_BIT)
-			return -1;
+	return MULTI_ENTRY_HDR_SIZE * CHAR_BIT;
+}
 
-		if (cfg->input_buf) {
-			memcpy(cfg->input_buf, cfg->icu_output_buf, data_size);
-			if (cmp_input_big_to_cpu_endianness(cfg->input_buf, data_size, cfg->data_type))
-				return -1;
-			strem_len_bit = data_size * CHAR_BIT;
-		}
 
-	} else {
-		switch (cfg->data_type) {
-		case DATA_TYPE_IMAGETTE:
-			strem_len_bit = decompress_imagette(cfg);
-			break;
-		default:
-			strem_len_bit = -1;
-			debug_print("Error: Compressed data type not supported.\n");
-			break;
-		}
+/**
+ * @brief decompress short normal light flux (S_FX) data
+ *
+ * @param cfg	pointer to the compression configuration structure
+ *
+ * @returns the bit length of the bitstream on success; negative on error,
+ *	CMP_ERROR_SAMLL_BUF if the bitstream buffer is too small to put the
+ *	value in the bitstream
+ */
+
+static int decompress_s_fx(const struct cmp_cfg *cfg)
+{
+	size_t i;
+	int stream_pos = 0;
+	uint32_t decoded_value;
+	struct decoder_setup setup_exp_flags, setup_fx;
+	struct s_fx *data_buf = cfg->input_buf;
+	struct s_fx *model_buf = cfg->model_buf;
+	struct s_fx *up_model_buf = NULL;
+	struct s_fx *next_model_p;
+	struct s_fx model;
+
+	if (model_mode_is_used(cfg->cmp_mode))
+		up_model_buf = cfg->icu_new_model_buf;
 
+	stream_pos = decompress_multi_entry_hdr((void **)&data_buf, (void **)&model_buf,
+						(void **)&up_model_buf, cfg);
+
+	if (model_mode_is_used(cfg->cmp_mode)) {
+		model = model_buf[0];
+		next_model_p = &model_buf[1];
+	} else {
+		memset(&model, 0, sizeof(model));
+		next_model_p = data_buf;
 	}
-	/* TODO: is this usefull? if (strem_len_bit != data_size * CHAR_BIT) { */
-	if (strem_len_bit <= 0)
+
+	if (configure_decoder_setup(&setup_exp_flags, cfg->cmp_par_exp_flags, cfg->spill_exp_flags,
+				    cfg->round, max_used_bits.s_exp_flags, cfg))
+		return -1;
+	if (configure_decoder_setup(&setup_fx, cfg->cmp_par_fx, cfg->spill_fx,
+				    cfg->round, max_used_bits.s_fx, cfg))
 		return -1;
 
+	for (i = 0; ; i++) {
+		stream_pos = decode_value(&decoded_value, model.exp_flags,
+					  stream_pos, &setup_exp_flags);
+		if (stream_pos <= 0)
+			return stream_pos;
+		data_buf[i].exp_flags = decoded_value;
+
+		stream_pos = decode_value(&decoded_value, model.fx, stream_pos,
+					  &setup_fx);
+		if (stream_pos <= 0)
+			return stream_pos;
+		data_buf[i].fx = decoded_value;
 
-	return data_size;
+		if (up_model_buf) {
+			up_model_buf[i].exp_flags = cmp_up_model(data_buf[i].exp_flags, model.exp_flags,
+								 cfg->model_value, setup_exp_flags.lossy_par);
+			up_model_buf[i].fx = cmp_up_model(data_buf[i].fx, model.fx,
+							  cfg->model_value, setup_fx.lossy_par);
+		}
+
+		if (i >= cfg->samples-1)
+			break;
+
+		model = next_model_p[i];
+	}
+	return stream_pos;
 }
 
 
-int decompress_cmp_entiy(struct cmp_entity *ent, void *model_buf,
-			 void *up_model_buf, void *decompressed_data)
+/**
+ * @brief decompress S_FX_DFX data
+ *
+ * @param cfg	pointer to the compression configuration structure
+ *
+ * @returns the bit length of the bitstream on success; negative on error,
+ *	CMP_ERROR_SAMLL_BUF if the bitstream buffer is too small to put the
+ *	value in the bitstream
+ */
+
+static int decompress_s_fx_efx(const struct cmp_cfg *cfg)
 {
-	int err;
-	struct cmp_cfg cfg = {0};
+	size_t i;
+	int stream_pos = 0;
+	uint32_t decoded_value;
+	struct decoder_setup setup_exp_flags, setup_fx, setup_efx;
+	struct s_fx_efx *data_buf = cfg->input_buf;
+	struct s_fx_efx *model_buf = cfg->model_buf;
+	struct s_fx_efx *up_model_buf = NULL;
+	struct s_fx_efx *next_model_p;
+	struct s_fx_efx model;
 
-	cfg.model_buf = model_buf;
-	cfg.icu_new_model_buf = up_model_buf;
-	cfg.input_buf = decompressed_data;
+	if (model_mode_is_used(cfg->cmp_mode))
+		up_model_buf = cfg->icu_new_model_buf;
 
-	if (!ent)
-		return -1;
+	stream_pos = decompress_multi_entry_hdr((void **)&data_buf, (void **)&model_buf,
+						(void **)&up_model_buf, cfg);
 
-	err = cmp_ent_read_header(ent, &cfg);
-	if (err)
+	if (model_mode_is_used(cfg->cmp_mode)) {
+		model = model_buf[0];
+		next_model_p = &model_buf[1];
+	} else {
+		memset(&model, 0, sizeof(model));
+		next_model_p = data_buf;
+	}
+
+	if (configure_decoder_setup(&setup_exp_flags, cfg->cmp_par_exp_flags, cfg->spill_exp_flags,
+				    cfg->round, max_used_bits.s_exp_flags, cfg))
+		return -1;
+	if (configure_decoder_setup(&setup_fx, cfg->cmp_par_fx, cfg->spill_fx,
+				    cfg->round, max_used_bits.s_fx, cfg))
+		return -1;
+	if (configure_decoder_setup(&setup_efx, cfg->cmp_par_efx, cfg->spill_efx,
+				    cfg->round, max_used_bits.s_efx, cfg))
 		return -1;
 
-	return decompressed_data_internal(&cfg);
+	for (i = 0; ; i++) {
+		stream_pos = decode_value(&decoded_value, model.exp_flags,
+					  stream_pos, &setup_exp_flags);
+		if (stream_pos <= 0)
+			return stream_pos;
+		data_buf[i].exp_flags = decoded_value;
+
+		stream_pos = decode_value(&decoded_value, model.fx, stream_pos,
+					  &setup_fx);
+		if (stream_pos <= 0)
+			return stream_pos;
+		data_buf[i].fx = decoded_value;
+
+		stream_pos = decode_value(&decoded_value, model.efx, stream_pos,
+					  &setup_efx);
+		if (stream_pos <= 0)
+			return stream_pos;
+		data_buf[i].efx = decoded_value;
+
+		if (up_model_buf) {
+			up_model_buf[i].exp_flags = cmp_up_model(data_buf[i].exp_flags, model.exp_flags,
+								 cfg->model_value, setup_exp_flags.lossy_par);
+			up_model_buf[i].fx = cmp_up_model(data_buf[i].fx, model.fx,
+							  cfg->model_value, setup_fx.lossy_par);
+			up_model_buf[i].efx = cmp_up_model(data_buf[i].efx, model.efx,
+							   cfg->model_value, setup_efx.lossy_par);
+		}
+
+		if (i >= cfg->samples-1)
+			break;
+
+		model = next_model_p[i];
+	}
+	return stream_pos;
 }
 
 
-/* model buffer is overwritten with updated model */
+/**
+ * @brief decompress short S_FX_NCOB data
+ *
+ * @param cfg	pointer to the compression configuration structure
+ *
+ * @returns the bit length of the bitstream on success; negative on error,
+ *	CMP_ERROR_SAMLL_BUF if the bitstream buffer is too small to put the
+ *	value in the bitstream
+ */
 
-int decompress_data(uint32_t *compressed_data, void *de_model_buf,
-		    const struct cmp_info *info, void *decompressed_data)
+static int decompress_s_fx_ncob(const struct cmp_cfg *cfg)
 {
-	int size_decomp_data;
-	struct cmp_cfg cfg = {0};
-
-	if (!compressed_data)
-		return -1;
+	size_t i;
+	int stream_pos = 0;
+	uint32_t decoded_value;
+	struct decoder_setup setup_exp_flags, setup_fx, setup_ncob;
+	struct s_fx_ncob *data_buf = cfg->input_buf;
+	struct s_fx_ncob *model_buf = cfg->model_buf;
+	struct s_fx_ncob *up_model_buf = NULL;
+	struct s_fx_ncob *next_model_p;
+	struct s_fx_ncob model;
 
-	if (!info)
-		return -1;
+	if (model_mode_is_used(cfg->cmp_mode))
+		up_model_buf = cfg->icu_new_model_buf;
 
-	if (info->cmp_err)
-		return -1;
+	stream_pos = decompress_multi_entry_hdr((void **)&data_buf, (void **)&model_buf,
+						(void **)&up_model_buf, cfg);
 
-	if (model_mode_is_used(info->cmp_mode_used))
-		if (!de_model_buf)
-			return -1;
-	/* TODO: add ohter modes */
+	if (model_mode_is_used(cfg->cmp_mode)) {
+		model = model_buf[0];
+		next_model_p = &model_buf[1];
+	} else {
+		memset(&model, 0, sizeof(model));
+		next_model_p = data_buf;
+	}
 
-	if (!decompressed_data)
+	if (configure_decoder_setup(&setup_exp_flags, cfg->cmp_par_exp_flags, cfg->spill_exp_flags,
+				    cfg->round, max_used_bits.s_exp_flags, cfg))
 		return -1;
-
-	/* cfg.data_type = info->data_type_used; */
-	cfg.cmp_mode = info->cmp_mode_used;
-	cfg.model_value = info->model_value_used;
-	cfg.round = info->round_used;
-	cfg.spill = info->spill_used;
-	cfg.golomb_par = info->golomb_par_used;
-	cfg.samples = info->samples_used;
-	cfg.icu_output_buf = compressed_data;
-	cfg.buffer_length = cmp_bit_to_4byte(info->cmp_size);
-	cfg.input_buf = decompressed_data;
-	cfg.model_buf = de_model_buf;
-	size_decomp_data = decompressed_data_internal(&cfg);
-	if (size_decomp_data <= 0)
+	if (configure_decoder_setup(&setup_fx, cfg->cmp_par_fx, cfg->spill_fx,
+				    cfg->round, max_used_bits.s_fx, cfg))
 		return -1;
-	else
-		return 0;
+	if (configure_decoder_setup(&setup_ncob, cfg->cmp_par_ncob, cfg->spill_ncob,
+				    cfg->round, max_used_bits.s_ncob, cfg))
+		return -1;
+
+	for (i = 0; ; i++) {
+		stream_pos = decode_value(&decoded_value, model.exp_flags,
+					  stream_pos, &setup_exp_flags);
+		if (stream_pos <= 0)
+			return stream_pos;
+		data_buf[i].exp_flags = decoded_value;
 
+		stream_pos = decode_value(&decoded_value, model.fx, stream_pos,
+					  &setup_fx);
+		if (stream_pos <= 0)
+			return stream_pos;
+		data_buf[i].fx = decoded_value;
 
+		stream_pos = decode_value(&decoded_value, model.ncob_x, stream_pos,
+					  &setup_ncob);
+		if (stream_pos <= 0)
+			return stream_pos;
+		data_buf[i].ncob_x = decoded_value;
+
+		stream_pos = decode_value(&decoded_value, model.ncob_y, stream_pos,
+					  &setup_ncob);
+		if (stream_pos <= 0)
+			return stream_pos;
+		data_buf[i].ncob_y = decoded_value;
+
+		if (up_model_buf) {
+			up_model_buf[i].exp_flags = cmp_up_model(data_buf[i].exp_flags, model.exp_flags,
+								 cfg->model_value, setup_exp_flags.lossy_par);
+			up_model_buf[i].fx = cmp_up_model(data_buf[i].fx, model.fx,
+							  cfg->model_value, setup_fx.lossy_par);
+			up_model_buf[i].ncob_x = cmp_up_model(data_buf[i].ncob_x, model.ncob_x,
+							      cfg->model_value, setup_ncob.lossy_par);
+			up_model_buf[i].ncob_y = cmp_up_model(data_buf[i].ncob_y, model.ncob_y,
+							      cfg->model_value, setup_ncob.lossy_par);
+		}
+
+		if (i >= cfg->samples-1)
+			break;
+
+		model = next_model_p[i];
+	}
+	return stream_pos;
+}
+
+
+/**
+ * @brief decompress short S_FX_NCOB_ECOB data
+ *
+ * @param cfg	pointer to the compression configuration structure
+ *
+ * @returns the bit length of the bitstream on success; negative on error,
+ *	CMP_ERROR_SAMLL_BUF if the bitstream buffer is too small to put the
+ *	value in the bitstream
+ */
+
+static int decompress_s_fx_efx_ncob_ecob(const struct cmp_cfg *cfg)
+{
+	size_t i;
+	int stream_pos = 0;
+	uint32_t decoded_value;
+	struct decoder_setup setup_exp_flags, setup_fx, setup_ncob, setup_efx, setup_ecob;
+	struct s_fx_efx_ncob_ecob *data_buf = cfg->input_buf;
+	struct s_fx_efx_ncob_ecob *model_buf = cfg->model_buf;
+	struct s_fx_efx_ncob_ecob *up_model_buf = NULL;
+	struct s_fx_efx_ncob_ecob *next_model_p;
+	struct s_fx_efx_ncob_ecob model;
+
+	if (model_mode_is_used(cfg->cmp_mode))
+		up_model_buf = cfg->icu_new_model_buf;
+
+	stream_pos = decompress_multi_entry_hdr((void **)&data_buf, (void **)&model_buf,
+						(void **)&up_model_buf, cfg);
+
+	if (model_mode_is_used(cfg->cmp_mode)) {
+		model = model_buf[0];
+		next_model_p = &model_buf[1];
+	} else {
+		memset(&model, 0, sizeof(model));
+		next_model_p = data_buf;
+	}
+
+	if (configure_decoder_setup(&setup_exp_flags, cfg->cmp_par_exp_flags, cfg->spill_exp_flags,
+				    cfg->round, max_used_bits.s_exp_flags, cfg))
+		return -1;
+	if (configure_decoder_setup(&setup_fx, cfg->cmp_par_fx, cfg->spill_fx,
+				    cfg->round, max_used_bits.s_fx, cfg))
+		return -1;
+	if (configure_decoder_setup(&setup_ncob, cfg->cmp_par_ncob, cfg->spill_ncob,
+				    cfg->round, max_used_bits.s_ncob, cfg))
+		return -1;
+	if (configure_decoder_setup(&setup_efx, cfg->cmp_par_efx, cfg->spill_efx,
+				    cfg->round, max_used_bits.s_efx, cfg))
+		return -1;
+	if (configure_decoder_setup(&setup_ecob, cfg->cmp_par_ecob, cfg->spill_ecob,
+				    cfg->round, max_used_bits.s_ecob, cfg))
+		return -1;
+
+	for (i = 0; ; i++) {
+		stream_pos = decode_value(&decoded_value, model.exp_flags,
+					  stream_pos, &setup_exp_flags);
+		if (stream_pos <= 0)
+			return stream_pos;
+		data_buf[i].exp_flags = decoded_value;
+
+		stream_pos = decode_value(&decoded_value, model.fx, stream_pos,
+					  &setup_fx);
+		if (stream_pos <= 0)
+			return stream_pos;
+		data_buf[i].fx = decoded_value;
+
+		stream_pos = decode_value(&decoded_value, model.ncob_x, stream_pos,
+					  &setup_ncob);
+		if (stream_pos <= 0)
+			return stream_pos;
+		data_buf[i].ncob_x = decoded_value;
+
+		stream_pos = decode_value(&decoded_value, model.ncob_y, stream_pos,
+					  &setup_ncob);
+		if (stream_pos <= 0)
+			return stream_pos;
+		data_buf[i].ncob_y = decoded_value;
+
+		stream_pos = decode_value(&decoded_value, model.efx, stream_pos,
+					  &setup_efx);
+		if (stream_pos <= 0)
+			return stream_pos;
+		data_buf[i].efx = decoded_value;
+
+		stream_pos = decode_value(&decoded_value, model.ecob_x, stream_pos,
+					  &setup_ecob);
+		if (stream_pos <= 0)
+			return stream_pos;
+		data_buf[i].ecob_x = decoded_value;
+
+		stream_pos = decode_value(&decoded_value, model.ecob_y, stream_pos,
+					  &setup_ecob);
+		if (stream_pos <= 0)
+			return stream_pos;
+		data_buf[i].ecob_y = decoded_value;
+
+		if (up_model_buf) {
+			up_model_buf[i].exp_flags = cmp_up_model(data_buf[i].exp_flags, model.exp_flags,
+								 cfg->model_value, setup_exp_flags.lossy_par);
+			up_model_buf[i].fx = cmp_up_model(data_buf[i].fx, model.fx,
+							  cfg->model_value, setup_fx.lossy_par);
+			up_model_buf[i].ncob_x = cmp_up_model(data_buf[i].ncob_x, model.ncob_x,
+							      cfg->model_value, setup_ncob.lossy_par);
+			up_model_buf[i].ncob_y = cmp_up_model(data_buf[i].ncob_y, model.ncob_y,
+							      cfg->model_value, setup_ncob.lossy_par);
+			up_model_buf[i].efx = cmp_up_model(data_buf[i].efx, model.efx,
+							   cfg->model_value, setup_efx.lossy_par);
+			up_model_buf[i].ecob_x = cmp_up_model(data_buf[i].ecob_x, model.ecob_x,
+							      cfg->model_value, setup_ecob.lossy_par);
+			up_model_buf[i].ecob_y = cmp_up_model(data_buf[i].ecob_y, model.ecob_y,
+							      cfg->model_value, setup_ecob.lossy_par);
+		}
+
+		if (i >= cfg->samples-1)
+			break;
+
+		model = next_model_p[i];
+	}
+	return stream_pos;
+}
+
+
+/**
+ * @brief decompress fast normal light flux (F_FX) data
+ *
+ * @param cfg	pointer to the compression configuration structure
+ *
+ * @returns the bit length of the bitstream on success; negative on error,
+ *	CMP_ERROR_SAMLL_BUF if the bitstream buffer is too small to put the
+ *	value in the bitstream
+ */
+
+static int decompress_f_fx(const struct cmp_cfg *cfg)
+{
+	size_t i;
+	int stream_pos = 0;
+	uint32_t decoded_value;
+	struct decoder_setup setup_fx;
+	struct f_fx *data_buf = cfg->input_buf;
+	struct f_fx *model_buf = cfg->model_buf;
+	struct f_fx *up_model_buf = NULL;
+	struct f_fx *next_model_p;
+	struct f_fx model;
+
+	if (model_mode_is_used(cfg->cmp_mode))
+		up_model_buf = cfg->icu_new_model_buf;
+
+	stream_pos = decompress_multi_entry_hdr((void **)&data_buf, (void **)&model_buf,
+						(void **)&up_model_buf, cfg);
+
+	if (model_mode_is_used(cfg->cmp_mode)) {
+		model = model_buf[0];
+		next_model_p = &model_buf[1];
+	} else {
+		memset(&model, 0, sizeof(model));
+		next_model_p = data_buf;
+	}
+
+	if (configure_decoder_setup(&setup_fx, cfg->cmp_par_fx, cfg->spill_fx,
+				    cfg->round, max_used_bits.f_fx, cfg))
+		return -1;
+
+	for (i = 0; ; i++) {
+		stream_pos = decode_value(&decoded_value, model.fx, stream_pos,
+					  &setup_fx);
+		if (stream_pos <= 0)
+			return stream_pos;
+		data_buf[i].fx = decoded_value;
+
+		if (up_model_buf)
+			up_model_buf[i].fx = cmp_up_model(data_buf[i].fx, model.fx,
+							  cfg->model_value, setup_fx.lossy_par);
+
+		if (i >= cfg->samples-1)
+			break;
+
+		model = next_model_p[i];
+	}
+	return stream_pos;
+}
+
+
+/**
+ * @brief decompress F_FX_DFX data
+ *
+ * @param cfg	pointer to the compression configuration structure
+ *
+ * @returns the bit length of the bitstream on success; negative on error,
+ *	CMP_ERROR_SAMLL_BUF if the bitstream buffer is too small to put the
+ *	value in the bitstream
+ */
+
+static int decompress_f_fx_efx(const struct cmp_cfg *cfg)
+{
+	size_t i;
+	int stream_pos = 0;
+	uint32_t decoded_value;
+	struct decoder_setup setup_fx, setup_efx;
+	struct f_fx_efx *data_buf = cfg->input_buf;
+	struct f_fx_efx *model_buf = cfg->model_buf;
+	struct f_fx_efx *up_model_buf = NULL;
+	struct f_fx_efx *next_model_p;
+	struct f_fx_efx model;
+
+	if (model_mode_is_used(cfg->cmp_mode))
+		up_model_buf = cfg->icu_new_model_buf;
+
+	stream_pos = decompress_multi_entry_hdr((void **)&data_buf, (void **)&model_buf,
+						(void **)&up_model_buf, cfg);
+
+	if (model_mode_is_used(cfg->cmp_mode)) {
+		model = model_buf[0];
+		next_model_p = &model_buf[1];
+	} else {
+		memset(&model, 0, sizeof(model));
+		next_model_p = data_buf;
+	}
+
+	if (configure_decoder_setup(&setup_fx, cfg->cmp_par_fx, cfg->spill_fx,
+				    cfg->round, max_used_bits.f_fx, cfg))
+		return -1;
+	if (configure_decoder_setup(&setup_efx, cfg->cmp_par_efx, cfg->spill_efx,
+				    cfg->round, max_used_bits.f_efx, cfg))
+		return -1;
+
+	for (i = 0; ; i++) {
+		stream_pos = decode_value(&decoded_value, model.fx, stream_pos,
+					  &setup_fx);
+		if (stream_pos <= 0)
+			return stream_pos;
+		data_buf[i].fx = decoded_value;
+
+		stream_pos = decode_value(&decoded_value, model.efx, stream_pos,
+					  &setup_efx);
+		if (stream_pos <= 0)
+			return stream_pos;
+		data_buf[i].efx = decoded_value;
+
+		if (up_model_buf) {
+			up_model_buf[i].fx = cmp_up_model(data_buf[i].fx, model.fx,
+							  cfg->model_value, setup_fx.lossy_par);
+			up_model_buf[i].efx = cmp_up_model(data_buf[i].efx, model.efx,
+							   cfg->model_value, setup_efx.lossy_par);
+		}
+
+		if (i >= cfg->samples-1)
+			break;
+
+		model = next_model_p[i];
+	}
+	return stream_pos;
+}
+
+
+/**
+ * @brief decompress short F_FX_NCOB data
+ *
+ * @param cfg	pointer to the compression configuration structure
+ *
+ * @returns the bit length of the bitstream on success; negative on error,
+ *	CMP_ERROR_SAMLL_BUF if the bitstream buffer is too small to put the
+ *	value in the bitstream
+ */
+
+static int decompress_f_fx_ncob(const struct cmp_cfg *cfg)
+{
+	size_t i;
+	int stream_pos = 0;
+	uint32_t decoded_value;
+	struct decoder_setup setup_fx, setup_ncob;
+	struct f_fx_ncob *data_buf = cfg->input_buf;
+	struct f_fx_ncob *model_buf = cfg->model_buf;
+	struct f_fx_ncob *up_model_buf = NULL;
+	struct f_fx_ncob *next_model_p;
+	struct f_fx_ncob model;
+
+	if (model_mode_is_used(cfg->cmp_mode))
+		up_model_buf = cfg->icu_new_model_buf;
+
+	stream_pos = decompress_multi_entry_hdr((void **)&data_buf, (void **)&model_buf,
+						(void **)&up_model_buf, cfg);
+
+	if (model_mode_is_used(cfg->cmp_mode)) {
+		model = model_buf[0];
+		next_model_p = &model_buf[1];
+	} else {
+		memset(&model, 0, sizeof(model));
+		next_model_p = data_buf;
+	}
+
+	if (configure_decoder_setup(&setup_fx, cfg->cmp_par_fx, cfg->spill_fx,
+				    cfg->round, max_used_bits.f_fx, cfg))
+		return -1;
+	if (configure_decoder_setup(&setup_ncob, cfg->cmp_par_ncob, cfg->spill_ncob,
+				    cfg->round, max_used_bits.f_ncob, cfg))
+		return -1;
+
+	for (i = 0; ; i++) {
+		stream_pos = decode_value(&decoded_value, model.fx, stream_pos,
+					  &setup_fx);
+		if (stream_pos <= 0)
+			return stream_pos;
+		data_buf[i].fx = decoded_value;
+
+		stream_pos = decode_value(&decoded_value, model.ncob_x, stream_pos,
+					  &setup_ncob);
+		if (stream_pos <= 0)
+			return stream_pos;
+		data_buf[i].ncob_x = decoded_value;
+
+		stream_pos = decode_value(&decoded_value, model.ncob_y, stream_pos,
+					  &setup_ncob);
+		if (stream_pos <= 0)
+			return stream_pos;
+		data_buf[i].ncob_y = decoded_value;
+
+		if (up_model_buf) {
+			up_model_buf[i].fx = cmp_up_model(data_buf[i].fx, model.fx,
+							  cfg->model_value, setup_fx.lossy_par);
+			up_model_buf[i].ncob_x = cmp_up_model(data_buf[i].ncob_x, model.ncob_x,
+							      cfg->model_value, setup_ncob.lossy_par);
+			up_model_buf[i].ncob_y = cmp_up_model(data_buf[i].ncob_y, model.ncob_y,
+							      cfg->model_value, setup_ncob.lossy_par);
+		}
+
+		if (i >= cfg->samples-1)
+			break;
+
+		model = next_model_p[i];
+	}
+	return stream_pos;
+}
+
+
+/**
+ * @brief decompress short F_FX_NCOB_ECOB data
+ *
+ * @param cfg	pointer to the compression configuration structure
+ *
+ * @returns the bit length of the bitstream on success; negative on error,
+ *	CMP_ERROR_SAMLL_BUF if the bitstream buffer is too small to put the
+ *	value in the bitstream
+ */
+
+static int decompress_f_fx_efx_ncob_ecob(const struct cmp_cfg *cfg)
+{
+	size_t i;
+	int stream_pos = 0;
+	uint32_t decoded_value;
+	struct decoder_setup setup_fx, setup_ncob, setup_efx, setup_ecob;
+	struct f_fx_efx_ncob_ecob *data_buf = cfg->input_buf;
+	struct f_fx_efx_ncob_ecob *model_buf = cfg->model_buf;
+	struct f_fx_efx_ncob_ecob *up_model_buf = NULL;
+	struct f_fx_efx_ncob_ecob *next_model_p;
+	struct f_fx_efx_ncob_ecob model;
+
+	if (model_mode_is_used(cfg->cmp_mode))
+		up_model_buf = cfg->icu_new_model_buf;
+
+	stream_pos = decompress_multi_entry_hdr((void **)&data_buf, (void **)&model_buf,
+						(void **)&up_model_buf, cfg);
+
+	if (model_mode_is_used(cfg->cmp_mode)) {
+		model = model_buf[0];
+		next_model_p = &model_buf[1];
+	} else {
+		memset(&model, 0, sizeof(model));
+		next_model_p = data_buf;
+	}
+
+	if (configure_decoder_setup(&setup_fx, cfg->cmp_par_fx, cfg->spill_fx,
+				    cfg->round, max_used_bits.f_fx, cfg))
+		return -1;
+	if (configure_decoder_setup(&setup_ncob, cfg->cmp_par_ncob, cfg->spill_ncob,
+				    cfg->round, max_used_bits.f_ncob, cfg))
+		return -1;
+	if (configure_decoder_setup(&setup_efx, cfg->cmp_par_efx, cfg->spill_efx,
+				    cfg->round, max_used_bits.f_efx, cfg))
+		return -1;
+	if (configure_decoder_setup(&setup_ecob, cfg->cmp_par_ecob, cfg->spill_ecob,
+				    cfg->round, max_used_bits.f_ecob, cfg))
+		return -1;
+
+	for (i = 0; ; i++) {
+		stream_pos = decode_value(&decoded_value, model.fx, stream_pos,
+					  &setup_fx);
+		if (stream_pos <= 0)
+			return stream_pos;
+		data_buf[i].fx = decoded_value;
+
+		stream_pos = decode_value(&decoded_value, model.ncob_x, stream_pos,
+					  &setup_ncob);
+		if (stream_pos <= 0)
+			return stream_pos;
+		data_buf[i].ncob_x = decoded_value;
+
+		stream_pos = decode_value(&decoded_value, model.ncob_y, stream_pos,
+					  &setup_ncob);
+		if (stream_pos <= 0)
+			return stream_pos;
+		data_buf[i].ncob_y = decoded_value;
+
+		stream_pos = decode_value(&decoded_value, model.efx, stream_pos,
+					  &setup_efx);
+		if (stream_pos <= 0)
+			return stream_pos;
+		data_buf[i].efx = decoded_value;
+
+		stream_pos = decode_value(&decoded_value, model.ecob_x, stream_pos,
+					  &setup_ecob);
+		if (stream_pos <= 0)
+			return stream_pos;
+		data_buf[i].ecob_x = decoded_value;
+
+		stream_pos = decode_value(&decoded_value, model.ecob_y, stream_pos,
+					  &setup_ecob);
+		if (stream_pos <= 0)
+			return stream_pos;
+		data_buf[i].ecob_y = decoded_value;
+
+		if (up_model_buf) {
+			up_model_buf[i].fx = cmp_up_model(data_buf[i].fx, model.fx,
+				cfg->model_value, setup_fx.lossy_par);
+			up_model_buf[i].ncob_x = cmp_up_model(data_buf[i].ncob_x, model.ncob_x,
+				cfg->model_value, setup_ncob.lossy_par);
+			up_model_buf[i].ncob_y = cmp_up_model(data_buf[i].ncob_y, model.ncob_y,
+				cfg->model_value, setup_ncob.lossy_par);
+			up_model_buf[i].efx = cmp_up_model(data_buf[i].efx, model.efx,
+				cfg->model_value, setup_efx.lossy_par);
+			up_model_buf[i].ecob_x = cmp_up_model(data_buf[i].ecob_x, model.ecob_x,
+				cfg->model_value, setup_ecob.lossy_par);
+			up_model_buf[i].ecob_y = cmp_up_model(data_buf[i].ecob_y, model.ecob_y,
+				cfg->model_value, setup_ecob.lossy_par);
+		}
+
+		if (i >= cfg->samples-1)
+			break;
+
+		model = next_model_p[i];
+	}
+	return stream_pos;
+}
+
+
+/**
+ * @brief decompress long normal light flux (L_FX) data
+ *
+ * @param cfg	pointer to the compression configuration structure
+ *
+ * @returns the bit length of the bitstream on success; negative on error,
+ *	CMP_ERROR_SAMLL_BUF if the bitstream buffer is too small to put the
+ *	value in the bitstream
+ */
+
+static int decompress_l_fx(const struct cmp_cfg *cfg)
+{
+	size_t i;
+	int stream_pos = 0;
+	uint32_t decoded_value;
+	struct decoder_setup setup_exp_flags, setup_fx, setup_fx_var;
+	struct l_fx *data_buf = cfg->input_buf;
+	struct l_fx *model_buf = cfg->model_buf;
+	struct l_fx *up_model_buf = NULL;
+	struct l_fx *next_model_p;
+	struct l_fx model;
+
+	if (model_mode_is_used(cfg->cmp_mode))
+		up_model_buf = cfg->icu_new_model_buf;
+
+	stream_pos = decompress_multi_entry_hdr((void **)&data_buf, (void **)&model_buf,
+						(void **)&up_model_buf, cfg);
+
+	if (model_mode_is_used(cfg->cmp_mode)) {
+		model = model_buf[0];
+		next_model_p = &model_buf[1];
+	} else {
+		memset(&model, 0, sizeof(model));
+		next_model_p = data_buf;
+	}
+
+	if (configure_decoder_setup(&setup_exp_flags, cfg->cmp_par_exp_flags, cfg->spill_exp_flags,
+				    cfg->round, max_used_bits.l_exp_flags, cfg))
+		return -1;
+	if (configure_decoder_setup(&setup_fx, cfg->cmp_par_fx, cfg->spill_fx,
+				    cfg->round, max_used_bits.l_fx, cfg))
+		return -1;
+	if (configure_decoder_setup(&setup_fx_var, cfg->cmp_par_fx_cob_variance, cfg->spill_fx_cob_variance,
+				    cfg->round, max_used_bits.l_fx_variance, cfg))
+		return -1;
+
+	for (i = 0; ; i++) {
+		stream_pos = decode_value(&decoded_value, model.exp_flags,
+					  stream_pos, &setup_exp_flags);
+		if (stream_pos <= 0)
+			return stream_pos;
+		data_buf[i].exp_flags = decoded_value;
+
+		stream_pos = decode_value(&decoded_value, model.fx, stream_pos,
+					  &setup_fx);
+		if (stream_pos <= 0)
+			return stream_pos;
+		data_buf[i].fx = decoded_value;
+
+		stream_pos = decode_value(&decoded_value, model.fx_variance, stream_pos,
+					  &setup_fx_var);
+		if (stream_pos <= 0)
+			return stream_pos;
+		data_buf[i].fx_variance = decoded_value;
+
+		if (up_model_buf) {
+			up_model_buf[i].exp_flags = cmp_up_model(data_buf[i].exp_flags, model.exp_flags,
+								 cfg->model_value, setup_exp_flags.lossy_par);
+			up_model_buf[i].fx = cmp_up_model(data_buf[i].fx, model.fx,
+							  cfg->model_value, setup_fx.lossy_par);
+			up_model_buf[i].fx_variance = cmp_up_model(data_buf[i].fx_variance, model.fx_variance,
+								   cfg->model_value, setup_fx_var.lossy_par);
+		}
+
+		if (i >= cfg->samples-1)
+			break;
+
+		model = next_model_p[i];
+	}
+	return stream_pos;
+}
+
+
+/**
+ * @brief decompress L_FX_EFX data
+ *
+ * @param cfg	pointer to the compression configuration structure
+ *
+ * @returns the bit length of the bitstream on success; negative on error,
+ *	CMP_ERROR_SAMLL_BUF if the bitstream buffer is too small to put the
+ *	value in the bitstream
+ */
+
+static int decompress_l_fx_efx(const struct cmp_cfg *cfg)
+{
+	size_t i;
+	int stream_pos = 0;
+	uint32_t decoded_value;
+	struct decoder_setup setup_exp_flags, setup_fx, setup_efx, setup_fx_var;
+	struct l_fx_efx *data_buf = cfg->input_buf;
+	struct l_fx_efx *model_buf = cfg->model_buf;
+	struct l_fx_efx *up_model_buf = NULL;
+	struct l_fx_efx *next_model_p;
+	struct l_fx_efx model;
+
+	if (model_mode_is_used(cfg->cmp_mode))
+		up_model_buf = cfg->icu_new_model_buf;
+
+	stream_pos = decompress_multi_entry_hdr((void **)&data_buf, (void **)&model_buf,
+						(void **)&up_model_buf, cfg);
+
+	if (model_mode_is_used(cfg->cmp_mode)) {
+		model = model_buf[0];
+		next_model_p = &model_buf[1];
+	} else {
+		memset(&model, 0, sizeof(model));
+		next_model_p = data_buf;
+	}
+
+	if (configure_decoder_setup(&setup_exp_flags, cfg->cmp_par_exp_flags, cfg->spill_exp_flags,
+				    cfg->round, max_used_bits.l_exp_flags, cfg))
+		return -1;
+	if (configure_decoder_setup(&setup_fx, cfg->cmp_par_fx, cfg->spill_fx,
+				    cfg->round, max_used_bits.l_fx, cfg))
+		return -1;
+	if (configure_decoder_setup(&setup_efx, cfg->cmp_par_efx, cfg->spill_efx,
+				    cfg->round, max_used_bits.l_efx, cfg))
+		return -1;
+	if (configure_decoder_setup(&setup_fx_var, cfg->cmp_par_fx_cob_variance, cfg->spill_fx_cob_variance,
+				    cfg->round, max_used_bits.l_fx_variance, cfg))
+		return -1;
+
+	for (i = 0; ; i++) {
+		stream_pos = decode_value(&decoded_value, model.exp_flags,
+					  stream_pos, &setup_exp_flags);
+		if (stream_pos <= 0)
+			return stream_pos;
+		data_buf[i].exp_flags = decoded_value;
+
+		stream_pos = decode_value(&decoded_value, model.fx, stream_pos,
+					  &setup_fx);
+		if (stream_pos <= 0)
+			return stream_pos;
+		data_buf[i].fx = decoded_value;
+
+		stream_pos = decode_value(&decoded_value, model.efx, stream_pos,
+					  &setup_efx);
+		if (stream_pos <= 0)
+			return stream_pos;
+		data_buf[i].efx = decoded_value;
+
+		stream_pos = decode_value(&decoded_value, model.fx_variance, stream_pos,
+					  &setup_fx_var);
+		if (stream_pos <= 0)
+			return stream_pos;
+		data_buf[i].fx_variance = decoded_value;
+
+		if (up_model_buf) {
+			up_model_buf[i].exp_flags = cmp_up_model(data_buf[i].exp_flags, model.exp_flags,
+								 cfg->model_value, setup_exp_flags.lossy_par);
+			up_model_buf[i].fx = cmp_up_model(data_buf[i].fx, model.fx,
+							  cfg->model_value, setup_fx.lossy_par);
+			up_model_buf[i].efx = cmp_up_model(data_buf[i].efx, model.efx,
+							   cfg->model_value, setup_efx.lossy_par);
+			up_model_buf[i].fx_variance = cmp_up_model(data_buf[i].fx_variance, model.fx_variance,
+								   cfg->model_value, setup_fx_var.lossy_par);
+		}
+
+		if (i >= cfg->samples-1)
+			break;
+
+		model = next_model_p[i];
+	}
+	return stream_pos;
+}
+
+
+/**
+ * @brief decompress L_FX_NCOB data
+ *
+ * @param cfg	pointer to the compression configuration structure
+ *
+ * @returns the bit length of the bitstream on success; negative on error,
+ *	CMP_ERROR_SAMLL_BUF if the bitstream buffer is too small to put the
+ *	value in the bitstream
+ */
+
+static int decompress_l_fx_ncob(const struct cmp_cfg *cfg)
+{
+	size_t i;
+	int stream_pos = 0;
+	uint32_t decoded_value;
+	struct decoder_setup setup_exp_flags, setup_fx, setup_ncob,
+			     setup_fx_var, setup_cob_var;
+	struct l_fx_ncob *data_buf = cfg->input_buf;
+	struct l_fx_ncob *model_buf = cfg->model_buf;
+	struct l_fx_ncob *up_model_buf = NULL;
+	struct l_fx_ncob *next_model_p;
+	struct l_fx_ncob model;
+
+	if (model_mode_is_used(cfg->cmp_mode))
+		up_model_buf = cfg->icu_new_model_buf;
+
+	stream_pos = decompress_multi_entry_hdr((void **)&data_buf, (void **)&model_buf,
+						(void **)&up_model_buf, cfg);
+
+	if (model_mode_is_used(cfg->cmp_mode)) {
+		model = model_buf[0];
+		next_model_p = &model_buf[1];
+	} else {
+		memset(&model, 0, sizeof(model));
+		next_model_p = data_buf;
+	}
+
+	if (configure_decoder_setup(&setup_exp_flags, cfg->cmp_par_exp_flags, cfg->spill_exp_flags,
+				    cfg->round, max_used_bits.l_exp_flags, cfg))
+		return -1;
+	if (configure_decoder_setup(&setup_fx, cfg->cmp_par_fx, cfg->spill_fx,
+				    cfg->round, max_used_bits.l_fx, cfg))
+		return -1;
+	if (configure_decoder_setup(&setup_ncob, cfg->cmp_par_ncob, cfg->spill_ncob,
+				    cfg->round, max_used_bits.l_ncob, cfg))
+		return -1;
+	if (configure_decoder_setup(&setup_fx_var, cfg->cmp_par_fx_cob_variance, cfg->spill_fx_cob_variance,
+				    cfg->round, max_used_bits.l_fx_variance, cfg))
+		return -1;
+	if (configure_decoder_setup(&setup_cob_var, cfg->cmp_par_fx_cob_variance, cfg->spill_fx_cob_variance,
+				    cfg->round, max_used_bits.l_cob_variance, cfg))
+		return -1;
+
+	for (i = 0; ; i++) {
+		stream_pos = decode_value(&decoded_value, model.exp_flags,
+					  stream_pos, &setup_exp_flags);
+		if (stream_pos <= 0)
+			return stream_pos;
+		data_buf[i].exp_flags = decoded_value;
+
+		stream_pos = decode_value(&decoded_value, model.fx, stream_pos,
+					  &setup_fx);
+		if (stream_pos <= 0)
+			return stream_pos;
+		data_buf[i].fx = decoded_value;
+
+		stream_pos = decode_value(&decoded_value, model.ncob_x,
+					  stream_pos, &setup_ncob);
+		if (stream_pos <= 0)
+			return stream_pos;
+		data_buf[i].ncob_x = decoded_value;
+
+		stream_pos = decode_value(&decoded_value, model.ncob_y,
+					  stream_pos, &setup_ncob);
+		if (stream_pos <= 0)
+			return stream_pos;
+		data_buf[i].ncob_y = decoded_value;
+
+		stream_pos = decode_value(&decoded_value, model.fx_variance,
+					  stream_pos, &setup_fx_var);
+		if (stream_pos <= 0)
+			return stream_pos;
+		data_buf[i].fx_variance = decoded_value;
+
+		stream_pos = decode_value(&decoded_value, model.cob_x_variance,
+					  stream_pos, &setup_cob_var);
+		if (stream_pos <= 0)
+			return stream_pos;
+		data_buf[i].cob_x_variance = decoded_value;
+
+		stream_pos = decode_value(&decoded_value, model.cob_y_variance,
+					  stream_pos, &setup_cob_var);
+		if (stream_pos <= 0)
+			return stream_pos;
+		data_buf[i].cob_y_variance = decoded_value;
+
+		if (up_model_buf) {
+			up_model_buf[i].exp_flags = cmp_up_model(data_buf[i].exp_flags, model.exp_flags,
+				cfg->model_value, setup_exp_flags.lossy_par);
+			up_model_buf[i].fx = cmp_up_model(data_buf[i].fx, model.fx,
+				cfg->model_value, setup_fx.lossy_par);
+			up_model_buf[i].ncob_x = cmp_up_model(data_buf[i].ncob_x, model.ncob_x,
+				cfg->model_value, setup_ncob.lossy_par);
+			up_model_buf[i].ncob_y = cmp_up_model(data_buf[i].ncob_y, model.ncob_y,
+				cfg->model_value, setup_ncob.lossy_par);
+			up_model_buf[i].fx_variance = cmp_up_model(data_buf[i].fx_variance, model.fx_variance,
+				cfg->model_value, setup_fx_var.lossy_par);
+			up_model_buf[i].cob_x_variance = cmp_up_model(data_buf[i].cob_x_variance, model.cob_x_variance,
+				cfg->model_value, setup_cob_var.lossy_par);
+			up_model_buf[i].cob_y_variance = cmp_up_model(data_buf[i].cob_y_variance, model.cob_y_variance,
+				cfg->model_value, setup_cob_var.lossy_par);
+		}
+
+		if (i >= cfg->samples-1)
+			break;
+
+		model = next_model_p[i];
+	}
+	return stream_pos;
+}
+
+
+/**
+ * @brief decompress L_FX_EFX_NCOB_ECOB data
+ *
+ * @param cfg	pointer to the compression configuration structure
+ *
+ * @returns the bit length of the bitstream on success; negative on error,
+ *	CMP_ERROR_SAMLL_BUF if the bitstream buffer is too small to put the
+ *	value in the bitstream
+ */
+
+static int decompress_l_fx_efx_ncob_ecob(const struct cmp_cfg *cfg)
+{
+	size_t i;
+	int stream_pos = 0;
+	uint32_t decoded_value;
+	struct decoder_setup setup_exp_flags, setup_fx, setup_ncob, setup_efx,
+			     setup_ecob, setup_fx_var, setup_cob_var;
+	struct l_fx_efx_ncob_ecob *data_buf = cfg->input_buf;
+	struct l_fx_efx_ncob_ecob *model_buf = cfg->model_buf;
+	struct l_fx_efx_ncob_ecob *up_model_buf = NULL;
+	struct l_fx_efx_ncob_ecob *next_model_p;
+	struct l_fx_efx_ncob_ecob model;
+
+	if (model_mode_is_used(cfg->cmp_mode))
+		up_model_buf = cfg->icu_new_model_buf;
+
+	stream_pos = decompress_multi_entry_hdr((void **)&data_buf, (void **)&model_buf,
+						(void **)&up_model_buf, cfg);
+
+	if (model_mode_is_used(cfg->cmp_mode)) {
+		model = model_buf[0];
+		next_model_p = &model_buf[1];
+	} else {
+		memset(&model, 0, sizeof(model));
+		next_model_p = data_buf;
+	}
+
+	if (configure_decoder_setup(&setup_exp_flags, cfg->cmp_par_exp_flags, cfg->spill_exp_flags,
+				    cfg->round, max_used_bits.l_exp_flags, cfg))
+		return -1;
+	if (configure_decoder_setup(&setup_fx, cfg->cmp_par_fx, cfg->spill_fx,
+				    cfg->round, max_used_bits.l_fx, cfg))
+		return -1;
+	if (configure_decoder_setup(&setup_ncob, cfg->cmp_par_ncob, cfg->spill_ncob,
+				    cfg->round, max_used_bits.l_ncob, cfg))
+		return -1;
+	if (configure_decoder_setup(&setup_efx, cfg->cmp_par_efx, cfg->spill_efx,
+				    cfg->round, max_used_bits.l_efx, cfg))
+		return -1;
+	if (configure_decoder_setup(&setup_ecob, cfg->cmp_par_ecob, cfg->spill_ecob,
+				    cfg->round, max_used_bits.l_ecob, cfg))
+		return -1;
+	if (configure_decoder_setup(&setup_fx_var, cfg->cmp_par_fx_cob_variance, cfg->spill_fx_cob_variance,
+				    cfg->round, max_used_bits.l_fx_variance, cfg))
+		return -1;
+	if (configure_decoder_setup(&setup_cob_var, cfg->cmp_par_fx_cob_variance, cfg->spill_fx_cob_variance,
+				    cfg->round, max_used_bits.l_cob_variance, cfg))
+		return -1;
+
+	for (i = 0; ; i++) {
+		stream_pos = decode_value(&decoded_value, model.exp_flags,
+					  stream_pos, &setup_exp_flags);
+		if (stream_pos <= 0)
+			return stream_pos;
+		data_buf[i].exp_flags = decoded_value;
+
+		stream_pos = decode_value(&decoded_value, model.fx, stream_pos,
+					  &setup_fx);
+		if (stream_pos <= 0)
+			return stream_pos;
+		data_buf[i].fx = decoded_value;
+
+		stream_pos = decode_value(&decoded_value, model.ncob_x,
+					  stream_pos, &setup_ncob);
+		if (stream_pos <= 0)
+			return stream_pos;
+		data_buf[i].ncob_x = decoded_value;
+
+		stream_pos = decode_value(&decoded_value, model.ncob_y,
+					  stream_pos, &setup_ncob);
+		if (stream_pos <= 0)
+			return stream_pos;
+		data_buf[i].ncob_y = decoded_value;
+
+		stream_pos = decode_value(&decoded_value, model.efx, stream_pos,
+					  &setup_efx);
+		if (stream_pos <= 0)
+			return stream_pos;
+		data_buf[i].efx = decoded_value;
+
+		stream_pos = decode_value(&decoded_value, model.ecob_x,
+					  stream_pos, &setup_ecob);
+		if (stream_pos <= 0)
+			return stream_pos;
+		data_buf[i].ecob_x = decoded_value;
+
+		stream_pos = decode_value(&decoded_value, model.ecob_y,
+					  stream_pos, &setup_ecob);
+		if (stream_pos <= 0)
+			return stream_pos;
+		data_buf[i].ecob_y = decoded_value;
+
+		stream_pos = decode_value(&decoded_value, model.fx_variance,
+					  stream_pos, &setup_fx_var);
+		if (stream_pos <= 0)
+			return stream_pos;
+		data_buf[i].fx_variance = decoded_value;
+
+		stream_pos = decode_value(&decoded_value, model.cob_x_variance,
+					  stream_pos, &setup_cob_var);
+		if (stream_pos <= 0)
+			return stream_pos;
+		data_buf[i].cob_x_variance = decoded_value;
+
+		stream_pos = decode_value(&decoded_value, model.cob_y_variance,
+					  stream_pos, &setup_cob_var);
+		if (stream_pos <= 0)
+			return stream_pos;
+		data_buf[i].cob_y_variance = decoded_value;
+
+		if (up_model_buf) {
+			up_model_buf[i].exp_flags = cmp_up_model(data_buf[i].exp_flags, model.exp_flags,
+				cfg->model_value, setup_exp_flags.lossy_par);
+			up_model_buf[i].fx = cmp_up_model(data_buf[i].fx, model.fx,
+				cfg->model_value, setup_fx.lossy_par);
+			up_model_buf[i].ncob_x = cmp_up_model(data_buf[i].ncob_x, model.ncob_x,
+				cfg->model_value, setup_ncob.lossy_par);
+			up_model_buf[i].ncob_y = cmp_up_model(data_buf[i].ncob_y, model.ncob_y,
+				cfg->model_value, setup_ncob.lossy_par);
+			up_model_buf[i].fx_variance = cmp_up_model(data_buf[i].fx_variance, model.fx_variance,
+				cfg->model_value, setup_fx_var.lossy_par);
+			up_model_buf[i].cob_x_variance = cmp_up_model(data_buf[i].cob_x_variance, model.cob_x_variance,
+				cfg->model_value, setup_cob_var.lossy_par);
+			up_model_buf[i].cob_y_variance = cmp_up_model(data_buf[i].cob_y_variance, model.cob_y_variance,
+				cfg->model_value, setup_cob_var.lossy_par);
+		}
+
+		if (i >= cfg->samples-1)
+			break;
+
+		model = next_model_p[i];
+	}
+	return stream_pos;
+}
+
+
+/**
+ * @brief decompress N-CAM offset data
+ *
+ * @param cfg	pointer to the compression configuration structure
+ *
+ * @returns the bit length of the bitstream on success; negative on error,
+ *	CMP_ERROR_SAMLL_BUF if the bitstream buffer is too small to put the
+ *	value in the bitstream
+ */
+
+static int decompress_nc_offset(const struct cmp_cfg *cfg)
+{
+	size_t i;
+	int stream_pos = 0;
+	uint32_t decoded_value;
+	struct decoder_setup setup_mean, setup_var;
+	struct nc_offset *data_buf = cfg->input_buf;
+	struct nc_offset *model_buf = cfg->model_buf;
+	struct nc_offset *up_model_buf = NULL;
+	struct nc_offset *next_model_p;
+	struct nc_offset model;
+
+	if (model_mode_is_used(cfg->cmp_mode))
+		up_model_buf = cfg->icu_new_model_buf;
+
+	stream_pos = decompress_multi_entry_hdr((void **)&data_buf, (void **)&model_buf,
+						(void **)&up_model_buf, cfg);
+
+	if (model_mode_is_used(cfg->cmp_mode)) {
+		model = model_buf[0];
+		next_model_p = &model_buf[1];
+	} else {
+		memset(&model, 0, sizeof(model));
+		next_model_p = data_buf;
+	}
+
+	if (configure_decoder_setup(&setup_mean, cfg->cmp_par_mean, cfg->spill_mean,
+				    cfg->round, max_used_bits.nc_offset_mean, cfg))
+		return -1;
+	if (configure_decoder_setup(&setup_var, cfg->cmp_par_variance, cfg->spill_variance,
+				    cfg->round, max_used_bits.nc_offset_variance, cfg))
+		return -1;
+
+	for (i = 0; ; i++) {
+		stream_pos = decode_value(&decoded_value, model.mean, stream_pos,
+					  &setup_mean);
+		if (stream_pos <= 0)
+			return stream_pos;
+		data_buf[i].mean = decoded_value;
+
+		stream_pos = decode_value(&decoded_value, model.variance, stream_pos,
+					  &setup_var);
+		if (stream_pos <= 0)
+			return stream_pos;
+		data_buf[i].variance = decoded_value;
+
+		if (up_model_buf) {
+			up_model_buf[i].mean = cmp_up_model(data_buf[i].mean,
+				model.mean, cfg->model_value, setup_mean.lossy_par);
+			up_model_buf[i].variance = cmp_up_model(data_buf[i].variance,
+				model.variance, cfg->model_value, setup_var.lossy_par);
+		}
+
+		if (i >= cfg->samples-1)
+			break;
+
+		model = next_model_p[i];
+	}
+	return stream_pos;
+}
+
+
+/**
+ * @brief decompress N-CAM background data
+ *
+ * @param cfg	pointer to the compression configuration structure
+ *
+ * @returns the bit length of the bitstream on success; negative on error,
+ *	CMP_ERROR_SAMLL_BUF if the bitstream buffer is too small to put the
+ *	value in the bitstream
+ */
+
+static int decompress_nc_background(const struct cmp_cfg *cfg)
+{
+	size_t i;
+	int stream_pos = 0;
+	uint32_t decoded_value;
+	struct decoder_setup setup_mean, setup_var, setup_pix;
+	struct nc_background *data_buf = cfg->input_buf;
+	struct nc_background *model_buf = cfg->model_buf;
+	struct nc_background *up_model_buf = NULL;
+	struct nc_background *next_model_p;
+	struct nc_background model;
+
+	if (model_mode_is_used(cfg->cmp_mode))
+		up_model_buf = cfg->icu_new_model_buf;
+
+	stream_pos = decompress_multi_entry_hdr((void **)&data_buf, (void **)&model_buf,
+						(void **)&up_model_buf, cfg);
+
+	if (model_mode_is_used(cfg->cmp_mode)) {
+		model = model_buf[0];
+		next_model_p = &model_buf[1];
+	} else {
+		memset(&model, 0, sizeof(model));
+		next_model_p = data_buf;
+	}
+
+	if (configure_decoder_setup(&setup_mean, cfg->cmp_par_mean, cfg->spill_mean,
+				    cfg->round, max_used_bits.nc_background_mean, cfg))
+		return -1;
+	if (configure_decoder_setup(&setup_var, cfg->cmp_par_variance, cfg->spill_variance,
+				    cfg->round, max_used_bits.nc_background_variance, cfg))
+		return -1;
+	if (configure_decoder_setup(&setup_pix, cfg->cmp_par_pixels_error, cfg->spill_pixels_error,
+				    cfg->round, max_used_bits.nc_background_outlier_pixels, cfg))
+		return -1;
+
+	for (i = 0; ; i++) {
+		stream_pos = decode_value(&decoded_value, model.mean, stream_pos,
+					  &setup_mean);
+		if (stream_pos <= 0)
+			return stream_pos;
+		data_buf[i].mean = decoded_value;
+
+		stream_pos = decode_value(&decoded_value, model.variance, stream_pos,
+					  &setup_var);
+		if (stream_pos <= 0)
+			return stream_pos;
+		data_buf[i].variance = decoded_value;
+
+		stream_pos = decode_value(&decoded_value, model.outlier_pixels, stream_pos,
+					  &setup_pix);
+		if (stream_pos <= 0)
+			return stream_pos;
+		data_buf[i].outlier_pixels = decoded_value;
+
+		if (up_model_buf) {
+			up_model_buf[i].mean = cmp_up_model(data_buf[i].mean,
+				model.mean, cfg->model_value, setup_mean.lossy_par);
+			up_model_buf[i].variance = cmp_up_model(data_buf[i].variance,
+				model.variance, cfg->model_value, setup_var.lossy_par);
+			up_model_buf[i].outlier_pixels = cmp_up_model(data_buf[i].outlier_pixels,
+				model.outlier_pixels, cfg->model_value, setup_pix.lossy_par);
+		}
+
+		if (i >= cfg->samples-1)
+			break;
+
+		model = next_model_p[i];
+	}
+	return stream_pos;
+}
+
+
+/**
+ * @brief decompress N-CAM smearing data
+ *
+ * @param cfg	pointer to the compression configuration structure
+ *
+ * @returns the bit length of the bitstream on success; negative on error,
+ *	CMP_ERROR_SAMLL_BUF if the bitstream buffer is too small to put the
+ *	value in the bitstream
+ */
+
+static int decompress_smearing(const struct cmp_cfg *cfg)
+{
+	size_t i;
+	int stream_pos = 0;
+	uint32_t decoded_value;
+	struct decoder_setup setup_mean, setup_var, setup_pix;
+	struct smearing *data_buf = cfg->input_buf;
+	struct smearing *model_buf = cfg->model_buf;
+	struct smearing *up_model_buf = NULL;
+	struct smearing *next_model_p;
+	struct smearing model;
+
+	if (model_mode_is_used(cfg->cmp_mode))
+		up_model_buf = cfg->icu_new_model_buf;
+
+	stream_pos = decompress_multi_entry_hdr((void **)&data_buf, (void **)&model_buf,
+						(void **)&up_model_buf, cfg);
+
+	if (model_mode_is_used(cfg->cmp_mode)) {
+		model = model_buf[0];
+		next_model_p = &model_buf[1];
+	} else {
+		memset(&model, 0, sizeof(model));
+		next_model_p = data_buf;
+	}
+
+	if (configure_decoder_setup(&setup_mean, cfg->cmp_par_mean, cfg->spill_mean,
+				    cfg->round, max_used_bits.smeating_mean, cfg))
+		return -1;
+	if (configure_decoder_setup(&setup_var, cfg->cmp_par_variance, cfg->spill_variance,
+				    cfg->round, max_used_bits.smeating_variance_mean, cfg))
+		return -1;
+	if (configure_decoder_setup(&setup_pix, cfg->cmp_par_pixels_error, cfg->spill_pixels_error,
+				    cfg->round, max_used_bits.smearing_outlier_pixels, cfg))
+		return -1;
+
+	for (i = 0; ; i++) {
+		stream_pos = decode_value(&decoded_value, model.mean, stream_pos,
+					  &setup_mean);
+		if (stream_pos <= 0)
+			return stream_pos;
+		data_buf[i].mean = decoded_value;
+
+		stream_pos = decode_value(&decoded_value, model.variance_mean, stream_pos,
+					  &setup_var);
+		if (stream_pos <= 0)
+			return stream_pos;
+		data_buf[i].variance_mean = decoded_value;
+
+		stream_pos = decode_value(&decoded_value, model.outlier_pixels, stream_pos,
+					  &setup_pix);
+		if (stream_pos <= 0)
+			return stream_pos;
+		data_buf[i].outlier_pixels = decoded_value;
+
+		if (up_model_buf) {
+			up_model_buf[i].mean = cmp_up_model(data_buf[i].mean,
+				model.mean, cfg->model_value, setup_mean.lossy_par);
+			up_model_buf[i].variance_mean = cmp_up_model(data_buf[i].variance_mean,
+				model.variance_mean, cfg->model_value, setup_var.lossy_par);
+			up_model_buf[i].outlier_pixels = cmp_up_model(data_buf[i].outlier_pixels,
+				model.outlier_pixels, cfg->model_value, setup_pix.lossy_par);
+		}
+
+		if (i >= cfg->samples-1)
+			break;
+
+		model = next_model_p[i];
+	}
+	return stream_pos;
+}
+
+
+static int decompressed_data_internal(struct cmp_cfg *cfg)
+{
+	int data_size, strem_len_bit = -1;
+
+	if (!cfg)
+		return 0; /* or -1? */
+	if (!cfg->icu_output_buf)
+		return -1;
+
+	data_size = cmp_cal_size_of_data(cfg->samples, cfg->data_type);
+	if (!cfg->input_buf || !data_size)
+		return data_size;
+
+	if (model_mode_is_used(cfg->cmp_mode))
+		if (!cfg->model_buf)
+			return -1;
+
+	if (cfg->cmp_mode == CMP_MODE_RAW) {
+
+		if ((unsigned int)data_size < cfg->buffer_length/CHAR_BIT)
+			return -1;
+
+		if (cfg->input_buf) {
+			memcpy(cfg->input_buf, cfg->icu_output_buf, data_size);
+			if (cmp_input_big_to_cpu_endianness(cfg->input_buf, data_size, cfg->data_type))
+				return -1;
+			strem_len_bit = data_size * CHAR_BIT;
+		}
+
+	} else {
+		switch (cfg->data_type) {
+		case DATA_TYPE_IMAGETTE:
+		case DATA_TYPE_IMAGETTE_ADAPTIVE:
+		case DATA_TYPE_SAT_IMAGETTE:
+		case DATA_TYPE_SAT_IMAGETTE_ADAPTIVE:
+		case DATA_TYPE_F_CAM_IMAGETTE:
+		case DATA_TYPE_F_CAM_IMAGETTE_ADAPTIVE:
+			strem_len_bit = decompress_imagette(cfg);
+			break;
+		case DATA_TYPE_S_FX:
+			strem_len_bit = decompress_s_fx(cfg);
+			break;
+		case DATA_TYPE_S_FX_DFX:
+			strem_len_bit = decompress_s_fx_efx(cfg);
+			break;
+		case DATA_TYPE_S_FX_NCOB:
+			strem_len_bit = decompress_s_fx_ncob(cfg);
+			break;
+		case DATA_TYPE_S_FX_DFX_NCOB_ECOB:
+			strem_len_bit = decompress_s_fx_efx_ncob_ecob(cfg);
+			break;
+
+		case DATA_TYPE_F_FX:
+			strem_len_bit = decompress_f_fx(cfg);
+			break;
+		case DATA_TYPE_F_FX_DFX:
+			strem_len_bit = decompress_f_fx_efx(cfg);
+			break;
+		case DATA_TYPE_F_FX_NCOB:
+			strem_len_bit = decompress_f_fx_ncob(cfg);
+			break;
+		case DATA_TYPE_F_FX_DFX_NCOB_ECOB:
+			strem_len_bit = decompress_f_fx_efx_ncob_ecob(cfg);
+			break;
+
+		case DATA_TYPE_L_FX:
+			strem_len_bit = decompress_l_fx(cfg);
+			break;
+		case DATA_TYPE_L_FX_DFX:
+			strem_len_bit = decompress_l_fx_efx(cfg);
+			break;
+		case DATA_TYPE_L_FX_NCOB:
+			strem_len_bit = decompress_l_fx_ncob(cfg);
+			break;
+		case DATA_TYPE_L_FX_DFX_NCOB_ECOB:
+			strem_len_bit = decompress_l_fx_efx_ncob_ecob(cfg);
+			break;
+
+		case DATA_TYPE_OFFSET:
+			strem_len_bit = decompress_nc_offset(cfg);
+			break;
+		case DATA_TYPE_BACKGROUND:
+			strem_len_bit = decompress_nc_background(cfg);
+			break;
+		case DATA_TYPE_SMEARING:
+			strem_len_bit = decompress_smearing(cfg);
+			break;
+
+		case DATA_TYPE_F_CAM_OFFSET:
+		case DATA_TYPE_F_CAM_BACKGROUND:
+		case DATA_TYPE_UNKNOWN:
+		default:
+			strem_len_bit = -1;
+			debug_print("Error: Compressed data type not supported.\n");
+			break;
+		}
+
+	}
+	/* TODO: is this usefull? if (strem_len_bit != data_size * CHAR_BIT) { */
+	if (strem_len_bit <= 0)
+		return -1;
+
+	return data_size;
+}
+
+
+int decompress_cmp_entiy(struct cmp_entity *ent, void *model_buf,
+			 void *up_model_buf, void *decompressed_data)
+{
+	int err;
+	struct cmp_cfg cfg = {0};
+
+	cfg.model_buf = model_buf;
+	cfg.icu_new_model_buf = up_model_buf;
+	cfg.input_buf = decompressed_data;
+
+	if (!ent)
+		return -1;
+
+	err = cmp_ent_read_header(ent, &cfg);
+	if (err)
+		return -1;
+
+	return decompressed_data_internal(&cfg);
+}
+
+
+/* model buffer is overwritten with updated model */
+
+int decompress_data(uint32_t *compressed_data, void *de_model_buf,
+		    const struct cmp_info *info, void *decompressed_data)
+{
+	int size_decomp_data;
+	struct cmp_cfg cfg = {0};
+
+	if (!compressed_data)
+		return -1;
+
+	if (!info)
+		return -1;
+
+	if (info->cmp_err)
+		return -1;
+
+	if (model_mode_is_used(info->cmp_mode_used))
+		if (!de_model_buf)
+			return -1;
+	/* TODO: add ohter modes */
+
+	if (!decompressed_data)
+		return -1;
+
+	/* cfg.data_type = info->data_type_used; */
+	cfg.cmp_mode = info->cmp_mode_used;
+	cfg.model_value = info->model_value_used;
+	cfg.round = info->round_used;
+	cfg.spill = info->spill_used;
+	cfg.golomb_par = info->golomb_par_used;
+	cfg.samples = info->samples_used;
+	cfg.icu_output_buf = compressed_data;
+	cfg.buffer_length = cmp_bit_to_4byte(info->cmp_size);
+	cfg.input_buf = decompressed_data;
+	cfg.model_buf = de_model_buf;
+	size_decomp_data = decompressed_data_internal(&cfg);
+	if (size_decomp_data <= 0)
+		return -1;
+	else
+		return 0;
 }
diff --git a/test/cmp_icu/test_decmp.c b/test/cmp_icu/test_decmp.c
index 523b64f978eed8a3b8babb81e50a1ec6d8b0dd80..cb00bb095f383bec7a264e31f64ce8c8957f084f 100644
--- a/test/cmp_icu/test_decmp.c
+++ b/test/cmp_icu/test_decmp.c
@@ -10,12 +10,14 @@
 #include "../../lib/decmp.c" /* .c file included to test static functions */
 
 
-/* returns the needed size of the compression entry header plus the max size of the
+/**
+ * returns the needed size of the compression entry header plus the max size of the
  * compressed data if ent ==  NULL if ent is set the size of the compression
- * entry */
+ * entry (entity header + compressed data)
+ */
 size_t icu_compress_data_entity(struct cmp_entity *ent, const struct cmp_cfg *cfg)
 {
-	size_t s, hdr_size;
+	size_t s;
 	struct cmp_cfg cfg_cpy;
 	int cmp_size_bits;
 
@@ -25,33 +27,38 @@ size_t icu_compress_data_entity(struct cmp_entity *ent, const struct cmp_cfg *cf
 	if (cfg->icu_output_buf)
 		debug_print("Warning the set buffer for the compressed data is ignored! The compressed data are write to the compression entry.");
 
-	if (!ent) {
-		s = cmp_cal_size_of_data(cfg->buffer_length, cfg->data_type);
-		if (!s)
-			return 0;
+	s = cmp_cal_size_of_data(cfg->buffer_length, cfg->data_type);
+	if (!s)
+		return 0;
+	/* we round down to the next 4-byte allied address because we access the
+	 * cmp_buffer in uint32_t words
+	 */
+	if (cfg->cmp_mode != CMP_MODE_RAW)
+		s &= ~0x3U;
 
-		hdr_size = cmp_ent_cal_hdr_size(cfg->data_type, cfg->cmp_mode == CMP_MODE_RAW);
-		if (!hdr_size)
-			return 0;
+	s = cmp_ent_create(ent, cfg->data_type, cfg->cmp_mode == CMP_MODE_RAW, s);
 
-		return s + hdr_size;
-	}
+	if (!ent || !s)
+		return s;
 
 	cfg_cpy = *cfg;
 	cfg_cpy.icu_output_buf = cmp_ent_get_data_buf(ent);
-
+	if (!cfg_cpy.icu_output_buf)
+		return 0;
 	cmp_size_bits = icu_compress_data(&cfg_cpy);
 	if (cmp_size_bits < 0)
 		return 0;
 
+	/* XXX overwrite the size of the compression entity with the size of the
+	 * actual size of the compressed data */
+	/* not all allocated memory is normally needed */
 	s = cmp_ent_create(ent, cfg->data_type, cfg->cmp_mode == CMP_MODE_RAW,
-					 cmp_bit_to_4byte(cmp_size_bits));
-	if (!s)
-		return 0;
+			   cmp_bit_to_4byte(cmp_size_bits));
 
 	if (cmp_ent_write_cmp_pars(ent, cfg, cmp_size_bits))
 		return 0;
 
+
 	return s;
 }
 
@@ -177,7 +184,7 @@ void test_decode_normal(void)
 		TEST_ASSERT_EQUAL_HEX(sample, decoded_value);
 	}
 
-	 /* TODO error case: negativ stream_pos */
+	 /* TODO error case: negative stream_pos */
 }
 
 
@@ -288,12 +295,75 @@ void test_decompress_imagette_model(void)
 	TEST_ASSERT_EQUAL_HEX(4, up_model[4]);
 }
 
+
+
+#define CMP_PAR_UNUSED 0 /*TODO: remove this*/
+#define DATA_SAMPLES 5
+void test_cmp_decmp_s_fx_diff(void)
+{
+	size_t s;
+	int err;
+
+	struct cmp_entity *ent;
+	const uint32_t MAX_VALUE = ~(~0U << MAX_USED_S_FX_BITS);
+	struct s_fx data_entry[DATA_SAMPLES] = {
+		{0,0}, {1,23}, {2,42}, {3,MAX_VALUE}, {3,MAX_VALUE>>1} };
+	uint8_t data_to_compress[MULTI_ENTRY_HDR_SIZE + sizeof(data_entry)];
+	struct s_fx *decompressed_data = NULL;
+	/* uint32_t *compressed_data = NULL; */
+	uint32_t compressed_data_len_samples = DATA_SAMPLES;
+	struct cmp_cfg cfg;
+
+	for (s = 0; s < MULTI_ENTRY_HDR_SIZE; s++)
+		data_to_compress[s] = s;
+	memcpy(&data_to_compress[MULTI_ENTRY_HDR_SIZE], data_entry, sizeof(data_entry));
+
+	cfg = cmp_cfg_icu_create(DATA_TYPE_S_FX, CMP_MODE_DIFF_MULTI,
+				 CMP_PAR_UNUSED, CMP_LOSSLESS);
+	TEST_ASSERT(cfg.data_type != DATA_TYPE_UNKNOWN);
+
+	s = cmp_cfg_icu_buffers(&cfg, data_to_compress, DATA_SAMPLES, NULL, NULL,
+				NULL, compressed_data_len_samples);
+	TEST_ASSERT_TRUE(s);
+
+	err = cmp_cfg_fx_cob(&cfg, 2, 6, 4, 14, CMP_PAR_UNUSED, CMP_PAR_UNUSED,
+			     CMP_PAR_UNUSED, CMP_PAR_UNUSED, CMP_PAR_UNUSED,
+			     CMP_PAR_UNUSED, CMP_PAR_UNUSED, CMP_PAR_UNUSED);
+	TEST_ASSERT_FALSE(err);
+
+	s = icu_compress_data_entity(NULL, &cfg);
+	TEST_ASSERT_TRUE(s);
+	ent = malloc(s); TEST_ASSERT_TRUE(ent);
+	s = icu_compress_data_entity(ent, &cfg);
+	TEST_ASSERT_TRUE(s);
+
+	/* now decompress the data */
+	s = decompress_cmp_entiy(ent, NULL, NULL, decompressed_data);
+	TEST_ASSERT_EQUAL_INT(cmp_cal_size_of_data(cfg.samples, cfg.data_type), s);
+	decompressed_data = malloc(s); TEST_ASSERT_TRUE(decompressed_data);
+	s = decompress_cmp_entiy(ent, NULL, NULL, decompressed_data);
+	TEST_ASSERT_EQUAL_INT(cmp_cal_size_of_data(cfg.samples, cfg.data_type), s);
+
+	TEST_ASSERT_FALSE(memcmp(data_to_compress, decompressed_data, s));
+	/* for (i = 0; i < samples; ++i) { */
+	/* 	printf("%u == %u (round: %u)\n", data[i], decompressed_data[i], round); */
+	/* 	uint32_t mask = ~0U << round; */
+	/* 	if ((data[i]&mask) != (decompressed_data[i]&mask)) */
+	/* 		TEST_ASSERT(0); */
+	/* 	if (model_mode_is_used(cmp_mode)) */
+	/* 		if (up_model[i] != de_up_model[i]) */
+	/* 			TEST_ASSERT(0); */
+	/* } */
+}
+#undef DATA_SAMPLES
+
+
 int my_random(unsigned int min, unsigned int max)
 {
-	if (max-min > RAND_MAX)
-		TEST_ASSERT(0);
 	if (min > max)
 		TEST_ASSERT(0);
+	if (max-min > RAND_MAX)
+		TEST_ASSERT(0);
 	return min + rand() / (RAND_MAX / (max - min + 1) + 1);
 }
 
@@ -394,7 +464,7 @@ void test_imagette_random(void)
 
 	/* create a compression configuration */
 	cfg = cmp_cfg_icu_create(data_type, cmp_mode, model_value, round);
-	TEST_ASSERT(cfg.data_type != DATA_TYPE_UNKOWN);
+	TEST_ASSERT(cfg.data_type != DATA_TYPE_UNKNOWN);
 
 
 	cmp_data_size = cmp_cfg_icu_buffers(&cfg, data, samples, model, up_model,
@@ -402,14 +472,14 @@ void test_imagette_random(void)
 	TEST_ASSERT_TRUE(cmp_data_size);
 
 	uint32_t golomb_par = my_random(MIN_RDCU_GOLOMB_PAR, MAX_RDCU_GOLOMB_PAR);
-	uint32_t max_spill = get_max_spill(golomb_par, data_type);
+	uint32_t max_spill = cmp_icu_max_spill(golomb_par);
 	TEST_ASSERT(max_spill > 1);
 	uint32_t spill = my_random(2, max_spill);
 
 	error = cmp_cfg_icu_imagette(&cfg, golomb_par, spill);
 	TEST_ASSERT_FALSE(error);
 
-	print_cfg(&cfg, 0);
+	/* print_cfg(&cfg, 0); */
 	s = icu_compress_data_entity(NULL, &cfg);
 	TEST_ASSERT_TRUE(s);
 	ent = malloc(s); TEST_ASSERT_TRUE(ent);
@@ -424,7 +494,7 @@ void test_imagette_random(void)
 	TEST_ASSERT_EQUAL_INT(samples * sizeof(*data), s);
 
 	for (i = 0; i < samples; ++i) {
-		printf("%u == %u (round: %u)\n", data[i], decompressed_data[i], round);
+		/* printf("%u == %u (round: %u)\n", data[i], decompressed_data[i], round); */
 		uint32_t mask = ~0U << round;
 		if ((data[i]&mask) != (decompressed_data[i]&mask))
 			TEST_ASSERT(0);
@@ -440,3 +510,227 @@ void test_imagette_random(void)
 	free(ent);
 	free(decompressed_data);
 }
+
+
+void test_s_fx_diff(void)
+{
+	size_t s, i;
+	uint8_t cmp_entity[88] = {
+		0x80, 0x00, 0x00, 0x09, 0x00, 0x00, 0x58, 0x00, 0x00, 0x20, 0x04, 0xEE, 0x21, 0xBD, 0xB0, 0x1C, 0x04, 0xEE, 0x21, 0xBD, 0xB0, 0x41, 0x00, 0x08, 0x02, 0x08, 0xD0, 0x10, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x0A, 0x00, 0x01, 0x00, 0x00, 0x0A, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0xAE, 0xDE, 0x00, 0x00, 0x00, 0x73, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x00,
+	};
+
+	uint8_t result_data[32] = {0};
+	struct multi_entry_hdr *hdr = (struct multi_entry_hdr *)result_data;
+	struct s_fx *data = (struct s_fx *)hdr->entry;
+	/* put some dummy data in the header*/
+	for (i = 0; i < sizeof(*hdr); ++i)
+		result_data[i] = i;
+	data[0].exp_flags = 0;
+	data[0].fx = 0;
+	data[1].exp_flags = 1;
+	data[1].fx = 0xFFFFFF;
+	data[2].exp_flags = 3;
+	data[2].fx = 0x7FFFFF;
+	data[3].exp_flags = 0;
+	data[3].fx = 0;
+
+	s = decompress_cmp_entiy((void *)cmp_entity, NULL, NULL, NULL);
+	TEST_ASSERT_EQUAL_INT(sizeof(result_data), s);
+	uint8_t *decompressed_data = malloc(s);
+	TEST_ASSERT_TRUE(decompressed_data);
+	s = decompress_cmp_entiy((void *)cmp_entity, NULL, NULL, decompressed_data);
+	TEST_ASSERT_EQUAL_INT(sizeof(result_data), s);
+	for (i = 0; i < s; ++i) {
+		TEST_ASSERT_EQUAL(result_data[i], decompressed_data[i]);
+	}
+}
+
+
+void test_s_fx_model(void)
+{
+	size_t s, i;
+	uint8_t compressed_data_buf[92] = {
+		0x80, 0x00, 0x00, 0x09, 0x00, 0x00, 0x5C, 0x00, 0x00, 0x20, 0x04, 0xF0, 0xC2, 0xD3, 0x47, 0xE4, 0x04, 0xF0, 0xC2, 0xD3, 0x48, 0x16, 0x00, 0x08, 0x03, 0x08, 0xD0, 0x10, 0x01, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x0A, 0x00, 0x01, 0x00, 0x00, 0x0A, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x3B, 0xFF, 0xFF, 0xEF, 0xFF, 0xFF, 0x5B, 0xFF, 0xFF, 0xEF, 0xFF, 0xFF, 0x5D, 0x80, 0x00, 0x00,
+	};
+	struct cmp_entity * cmp_entity = (struct cmp_entity *)compressed_data_buf;
+
+	uint8_t model_buf[32];
+	uint8_t decompressed_data[32];
+	uint8_t up_model_buf[32];
+	uint8_t exp_data_buf[32] = {0}; /* expected uncompressed data */
+	uint8_t exp_up_model_buf[32] = {0};
+
+	struct multi_entry_hdr *model_collection = (struct multi_entry_hdr *)model_buf;
+	struct s_fx *model_data = (struct s_fx *)model_collection->entry;
+
+	memset(model_collection, 0xFF, sizeof(*model_collection));
+	model_data[0].exp_flags = 0;
+	model_data[0].fx = 0;
+	model_data[1].exp_flags = 3;
+	model_data[1].fx = 0x7FFFFF;
+	model_data[2].exp_flags = 0;
+	model_data[2].fx = 0xFFFFFF;
+	model_data[3].exp_flags = 3;
+	model_data[3].fx = 0xFFFFFF;
+
+	struct multi_entry_hdr *exp_data_collection = (struct multi_entry_hdr *)exp_data_buf;
+	struct s_fx *exp_data = (struct s_fx *)exp_data_collection->entry;
+	/* put some dummy data in the header */
+	for (i = 0; i < sizeof(*exp_data_collection); i++)
+		exp_data_buf[i] = i;
+	exp_data[0].exp_flags = 0;
+	exp_data[0].fx = 0;
+	exp_data[1].exp_flags = 1;
+	exp_data[1].fx = 0xFFFFFF;
+	exp_data[2].exp_flags = 3;
+	exp_data[2].fx = 0x7FFFFF;
+	exp_data[3].exp_flags = 0;
+	exp_data[3].fx = 0;
+
+	struct multi_entry_hdr *exp_up_model_collection = (struct multi_entry_hdr *)exp_up_model_buf;
+	struct s_fx *exp_updated_model_data = (struct s_fx *)exp_up_model_collection->entry;
+	/* put some dummy data in the header*/
+	for (i = 0; i < sizeof(*exp_up_model_collection); i++)
+		exp_up_model_buf[i] = i;
+	exp_updated_model_data[0].exp_flags = 0;
+	exp_updated_model_data[0].fx = 0;
+	exp_updated_model_data[1].exp_flags = 2;
+	exp_updated_model_data[1].fx = 0xBFFFFF;
+	exp_updated_model_data[2].exp_flags = 1;
+	exp_updated_model_data[2].fx = 0xBFFFFF;
+	exp_updated_model_data[3].exp_flags = 1;
+	exp_updated_model_data[3].fx = 0x7FFFFF;
+
+	s = decompress_cmp_entiy(cmp_entity, model_buf, up_model_buf, decompressed_data);
+	TEST_ASSERT_EQUAL_INT(sizeof(exp_data_buf), s);
+
+	TEST_ASSERT_FALSE(memcmp(exp_data_buf, decompressed_data, s));
+	TEST_ASSERT_FALSE(memcmp(exp_up_model_buf, up_model_buf, s));
+}
+
+/* TODO: implement this! */
+void generate_random_test_data(void *data, int samples,
+			       enum cmp_data_type data_type)
+{
+	int s = cmp_cal_size_of_data(samples, data_type);
+	memset(data, 0x0, s);
+}
+
+
+void test_random_compression_decompression(void)
+{
+	size_t s;
+	struct cmp_cfg cfg = {0};
+	struct cmp_entity *cmp_ent;
+	void *decompressed_data;
+	void *decompressed_up_model = NULL;
+
+	srand(0); /* TODO:XXX*/
+	puts("--------------------------------------------------------------");
+
+	/* for (cfg.data_type = DATA_TYPE_IMAGETTE; TODO:!! implement this */
+	/*      cfg.data_type < DATA_TYPE_F_CAM_BACKGROUND+1; cfg.data_type++) { */
+	for (cfg.data_type = DATA_TYPE_IMAGETTE;
+	     cfg.data_type < DATA_TYPE_F_CAM_IMAGETTE_ADAPTIVE+1; cfg.data_type++) {
+		cfg.samples = my_random(1,0x30000);
+			if (cfg.data_type == DATA_TYPE_OFFSET)
+				puts("FADF");
+
+		cfg.buffer_length = (CMP_ENTITY_MAX_SIZE - NON_IMAGETTE_HEADER_SIZE - MULTI_ENTRY_HDR_SIZE)/size_of_a_sample(cfg.data_type);;
+		s = cmp_cal_size_of_data(cfg.samples, cfg.data_type);
+		printf("%s\n", data_type2string(cfg.data_type));
+		TEST_ASSERT_TRUE(s);
+		cfg.input_buf = calloc(1, s);
+		TEST_ASSERT_NOT_NULL(cfg.input_buf);
+		cfg.model_buf = calloc(1, s);
+		TEST_ASSERT_TRUE(cfg.model_buf);
+		decompressed_data = calloc(1, s);
+		TEST_ASSERT_NOT_NULL(decompressed_data);
+		cfg.icu_new_model_buf = calloc(1, s);
+		TEST_ASSERT_TRUE(cfg.icu_new_model_buf);
+		decompressed_up_model = calloc(1, s);
+		TEST_ASSERT_TRUE(decompressed_up_model);
+		cmp_ent = calloc(1, CMP_ENTITY_MAX_SIZE);
+
+		generate_random_test_data(cfg.input_buf, cfg.samples, cfg.data_type);
+		generate_random_test_data(cfg.model_buf, cfg.samples, cfg.data_type);
+
+		cfg.model_value = my_random(0,16);
+		/* cfg.round = my_random(0,3); /1* XXX *1/ */
+		cfg.round = 0;
+
+		cfg.golomb_par = my_random(MIN_RDCU_GOLOMB_PAR, MAX_RDCU_GOLOMB_PAR);
+		cfg.ap1_golomb_par = my_random(MIN_RDCU_GOLOMB_PAR, MAX_RDCU_GOLOMB_PAR);
+		cfg.ap2_golomb_par = my_random(MIN_RDCU_GOLOMB_PAR, MAX_RDCU_GOLOMB_PAR);
+		cfg.cmp_par_exp_flags = my_random(MIN_ICU_GOLOMB_PAR, MAX_ICU_GOLOMB_PAR);
+		cfg.cmp_par_fx = my_random(MIN_ICU_GOLOMB_PAR, MAX_ICU_GOLOMB_PAR);
+		cfg.cmp_par_ncob = my_random(MIN_ICU_GOLOMB_PAR, MAX_ICU_GOLOMB_PAR);
+		cfg.cmp_par_efx = my_random(MIN_ICU_GOLOMB_PAR, MAX_ICU_GOLOMB_PAR);
+		cfg.cmp_par_ecob = my_random(MIN_ICU_GOLOMB_PAR, MAX_ICU_GOLOMB_PAR);
+		cfg.cmp_par_fx_cob_variance = my_random(MIN_ICU_GOLOMB_PAR, MAX_ICU_GOLOMB_PAR);
+		cfg.cmp_par_mean = my_random(MIN_ICU_GOLOMB_PAR, MAX_ICU_GOLOMB_PAR);
+		cfg.cmp_par_variance = my_random(MIN_ICU_GOLOMB_PAR, MAX_ICU_GOLOMB_PAR);
+		cfg.cmp_par_pixels_error = my_random(MIN_ICU_GOLOMB_PAR, MAX_ICU_GOLOMB_PAR);
+
+		cfg.spill = my_random(MIN_RDCU_SPILL, cmp_icu_max_spill(cfg.golomb_par));
+		cfg.ap1_spill = my_random(MIN_RDCU_SPILL, cmp_icu_max_spill(cfg.ap1_golomb_par));
+		cfg.ap2_spill = my_random(MIN_RDCU_SPILL, cmp_icu_max_spill(cfg.ap2_golomb_par));
+		if (!rdcu_supported_data_type_is_used(cfg.data_type)) {
+			cfg.spill_exp_flags = my_random(MIN_ICU_SPILL, cmp_icu_max_spill(cfg.cmp_par_exp_flags));
+			cfg.spill_fx = my_random(MIN_ICU_SPILL, cmp_icu_max_spill(cfg.cmp_par_fx));
+			cfg.spill_ncob = my_random(MIN_ICU_SPILL, cmp_icu_max_spill(cfg.cmp_par_ncob));
+			cfg.spill_efx = my_random(MIN_ICU_SPILL, cmp_icu_max_spill(cfg.cmp_par_efx));
+			cfg.spill_ecob = my_random(MIN_ICU_SPILL, cmp_icu_max_spill(cfg.cmp_par_ecob));
+			cfg.spill_fx_cob_variance = my_random(MIN_ICU_SPILL, cmp_icu_max_spill(cfg.cmp_par_fx_cob_variance));
+			cfg.spill_mean = my_random(MIN_ICU_SPILL, cmp_icu_max_spill(cfg.cmp_par_mean));
+			cfg.spill_variance = my_random(MIN_ICU_SPILL, cmp_icu_max_spill(cfg.cmp_par_variance));
+			cfg.spill_pixels_error = my_random(MIN_ICU_SPILL, cmp_icu_max_spill(cfg.cmp_par_pixels_error));
+		}
+
+		for (cfg.cmp_mode = CMP_MODE_RAW; cfg.cmp_mode < CMP_MODE_STUFF; cfg.cmp_mode++) {
+			int cmp_size, decompress_size;
+
+			cmp_size = icu_compress_data_entity(cmp_ent, &cfg);
+			if (cmp_size <= 0) {
+				printf("cmp_size: %i\n", cmp_size);
+				print_cfg(&cfg, 0);
+			}
+			TEST_ASSERT_GREATER_THAN(0, cmp_size);
+
+			/* now decompress the data */
+			decompress_size = decompress_cmp_entiy(cmp_ent, cfg.model_buf,
+							       decompressed_up_model, decompressed_data);
+
+			TEST_ASSERT_EQUAL_INT(s, decompress_size);
+			if (memcmp(cfg.input_buf, decompressed_data, s)) {
+				print_cfg(&cfg, 0);
+				TEST_ASSERT_FALSE(memcmp(cfg.input_buf, decompressed_data, s));
+			}
+			if (model_mode_is_used(cfg.cmp_mode))
+				TEST_ASSERT_FALSE(memcmp(cfg.icu_new_model_buf, decompressed_up_model, s));
+
+			memset(cmp_ent, 0, CMP_ENTITY_MAX_SIZE);
+			memset(decompressed_data, 0, s);
+			memset(decompressed_up_model, 0, s);
+			memset(cfg.icu_new_model_buf, 0, s);
+		}
+
+		free(cfg.model_buf);
+		cfg.model_buf = NULL;
+		free(cfg.input_buf);
+		cfg.input_buf = NULL;
+		free(cfg.icu_new_model_buf);
+		cfg.icu_new_model_buf = NULL;
+		free(cmp_ent);
+		cmp_ent = NULL;
+		free(decompressed_data);
+		decompressed_data = NULL;
+		free(decompressed_up_model);
+		decompressed_up_model = NULL;
+
+	}
+}