(root)/
xz-5.4.5/
src/
liblzma/
common/
index_encoder.c
       1  ///////////////////////////////////////////////////////////////////////////////
       2  //
       3  /// \file       index_encoder.c
       4  /// \brief      Encodes the Index field
       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 "index_encoder.h"
      14  #include "index.h"
      15  #include "check.h"
      16  
      17  
      18  typedef struct {
      19  	enum {
      20  		SEQ_INDICATOR,
      21  		SEQ_COUNT,
      22  		SEQ_UNPADDED,
      23  		SEQ_UNCOMPRESSED,
      24  		SEQ_NEXT,
      25  		SEQ_PADDING,
      26  		SEQ_CRC32,
      27  	} sequence;
      28  
      29  	/// Index being encoded
      30  	const lzma_index *index;
      31  
      32  	/// Iterator for the Index being encoded
      33  	lzma_index_iter iter;
      34  
      35  	/// Position in integers
      36  	size_t pos;
      37  
      38  	/// CRC32 of the List of Records field
      39  	uint32_t crc32;
      40  } lzma_index_coder;
      41  
      42  
      43  static lzma_ret
      44  index_encode(void *coder_ptr,
      45  		const lzma_allocator *allocator lzma_attribute((__unused__)),
      46  		const uint8_t *restrict in lzma_attribute((__unused__)),
      47  		size_t *restrict in_pos lzma_attribute((__unused__)),
      48  		size_t in_size lzma_attribute((__unused__)),
      49  		uint8_t *restrict out, size_t *restrict out_pos,
      50  		size_t out_size,
      51  		lzma_action action lzma_attribute((__unused__)))
      52  {
      53  	lzma_index_coder *coder = coder_ptr;
      54  
      55  	// Position where to start calculating CRC32. The idea is that we
      56  	// need to call lzma_crc32() only once per call to index_encode().
      57  	const size_t out_start = *out_pos;
      58  
      59  	// Return value to use if we return at the end of this function.
      60  	// We use "goto out" to jump out of the while-switch construct
      61  	// instead of returning directly, because that way we don't need
      62  	// to copypaste the lzma_crc32() call to many places.
      63  	lzma_ret ret = LZMA_OK;
      64  
      65  	while (*out_pos < out_size)
      66  	switch (coder->sequence) {
      67  	case SEQ_INDICATOR:
      68  		out[*out_pos] = INDEX_INDICATOR;
      69  		++*out_pos;
      70  		coder->sequence = SEQ_COUNT;
      71  		break;
      72  
      73  	case SEQ_COUNT: {
      74  		const lzma_vli count = lzma_index_block_count(coder->index);
      75  		ret = lzma_vli_encode(count, &coder->pos,
      76  				out, out_pos, out_size);
      77  		if (ret != LZMA_STREAM_END)
      78  			goto out;
      79  
      80  		ret = LZMA_OK;
      81  		coder->pos = 0;
      82  		coder->sequence = SEQ_NEXT;
      83  		break;
      84  	}
      85  
      86  	case SEQ_NEXT:
      87  		if (lzma_index_iter_next(
      88  				&coder->iter, LZMA_INDEX_ITER_BLOCK)) {
      89  			// Get the size of the Index Padding field.
      90  			coder->pos = lzma_index_padding_size(coder->index);
      91  			assert(coder->pos <= 3);
      92  			coder->sequence = SEQ_PADDING;
      93  			break;
      94  		}
      95  
      96  		coder->sequence = SEQ_UNPADDED;
      97  
      98  	// Fall through
      99  
     100  	case SEQ_UNPADDED:
     101  	case SEQ_UNCOMPRESSED: {
     102  		const lzma_vli size = coder->sequence == SEQ_UNPADDED
     103  				? coder->iter.block.unpadded_size
     104  				: coder->iter.block.uncompressed_size;
     105  
     106  		ret = lzma_vli_encode(size, &coder->pos,
     107  				out, out_pos, out_size);
     108  		if (ret != LZMA_STREAM_END)
     109  			goto out;
     110  
     111  		ret = LZMA_OK;
     112  		coder->pos = 0;
     113  
     114  		// Advance to SEQ_UNCOMPRESSED or SEQ_NEXT.
     115  		++coder->sequence;
     116  		break;
     117  	}
     118  
     119  	case SEQ_PADDING:
     120  		if (coder->pos > 0) {
     121  			--coder->pos;
     122  			out[(*out_pos)++] = 0x00;
     123  			break;
     124  		}
     125  
     126  		// Finish the CRC32 calculation.
     127  		coder->crc32 = lzma_crc32(out + out_start,
     128  				*out_pos - out_start, coder->crc32);
     129  
     130  		coder->sequence = SEQ_CRC32;
     131  
     132  	// Fall through
     133  
     134  	case SEQ_CRC32:
     135  		// We don't use the main loop, because we don't want
     136  		// coder->crc32 to be touched anymore.
     137  		do {
     138  			if (*out_pos == out_size)
     139  				return LZMA_OK;
     140  
     141  			out[*out_pos] = (coder->crc32 >> (coder->pos * 8))
     142  					& 0xFF;
     143  			++*out_pos;
     144  
     145  		} while (++coder->pos < 4);
     146  
     147  		return LZMA_STREAM_END;
     148  
     149  	default:
     150  		assert(0);
     151  		return LZMA_PROG_ERROR;
     152  	}
     153  
     154  out:
     155  	// Update the CRC32.
     156  	//
     157  	// Avoid null pointer + 0 (undefined behavior) in "out + out_start".
     158  	// In such a case we had no input and thus out_used == 0.
     159  	{
     160  		const size_t out_used = *out_pos - out_start;
     161  		if (out_used > 0)
     162  			coder->crc32 = lzma_crc32(out + out_start,
     163  					out_used, coder->crc32);
     164  	}
     165  
     166  	return ret;
     167  }
     168  
     169  
     170  static void
     171  index_encoder_end(void *coder, const lzma_allocator *allocator)
     172  {
     173  	lzma_free(coder, allocator);
     174  	return;
     175  }
     176  
     177  
     178  static void
     179  index_encoder_reset(lzma_index_coder *coder, const lzma_index *i)
     180  {
     181  	lzma_index_iter_init(&coder->iter, i);
     182  
     183  	coder->sequence = SEQ_INDICATOR;
     184  	coder->index = i;
     185  	coder->pos = 0;
     186  	coder->crc32 = 0;
     187  
     188  	return;
     189  }
     190  
     191  
     192  extern lzma_ret
     193  lzma_index_encoder_init(lzma_next_coder *next, const lzma_allocator *allocator,
     194  		const lzma_index *i)
     195  {
     196  	lzma_next_coder_init(&lzma_index_encoder_init, next, allocator);
     197  
     198  	if (i == NULL)
     199  		return LZMA_PROG_ERROR;
     200  
     201  	if (next->coder == NULL) {
     202  		next->coder = lzma_alloc(sizeof(lzma_index_coder), allocator);
     203  		if (next->coder == NULL)
     204  			return LZMA_MEM_ERROR;
     205  
     206  		next->code = &index_encode;
     207  		next->end = &index_encoder_end;
     208  	}
     209  
     210  	index_encoder_reset(next->coder, i);
     211  
     212  	return LZMA_OK;
     213  }
     214  
     215  
     216  extern LZMA_API(lzma_ret)
     217  lzma_index_encoder(lzma_stream *strm, const lzma_index *i)
     218  {
     219  	lzma_next_strm_init(lzma_index_encoder_init, strm, i);
     220  
     221  	strm->internal->supported_actions[LZMA_RUN] = true;
     222  	strm->internal->supported_actions[LZMA_FINISH] = true;
     223  
     224  	return LZMA_OK;
     225  }
     226  
     227  
     228  extern LZMA_API(lzma_ret)
     229  lzma_index_buffer_encode(const lzma_index *i,
     230  		uint8_t *out, size_t *out_pos, size_t out_size)
     231  {
     232  	// Validate the arguments.
     233  	if (i == NULL || out == NULL || out_pos == NULL || *out_pos > out_size)
     234  		return LZMA_PROG_ERROR;
     235  
     236  	// Don't try to encode if there's not enough output space.
     237  	if (out_size - *out_pos < lzma_index_size(i))
     238  		return LZMA_BUF_ERROR;
     239  
     240  	// The Index encoder needs just one small data structure so we can
     241  	// allocate it on stack.
     242  	lzma_index_coder coder;
     243  	index_encoder_reset(&coder, i);
     244  
     245  	// Do the actual encoding. This should never fail, but store
     246  	// the original *out_pos just in case.
     247  	const size_t out_start = *out_pos;
     248  	lzma_ret ret = index_encode(&coder, NULL, NULL, NULL, 0,
     249  			out, out_pos, out_size, LZMA_RUN);
     250  
     251  	if (ret == LZMA_STREAM_END) {
     252  		ret = LZMA_OK;
     253  	} else {
     254  		// We should never get here, but just in case, restore the
     255  		// output position and set the error accordingly if something
     256  		// goes wrong and debugging isn't enabled.
     257  		assert(0);
     258  		*out_pos = out_start;
     259  		ret = LZMA_PROG_ERROR;
     260  	}
     261  
     262  	return ret;
     263  }