root/src/liblzma/common/index_decoder.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. index_decode
  2. index_decoder_end
  3. index_decoder_memconfig
  4. index_decoder_reset
  5. index_decoder_init
  6. LZMA_API
  7. LZMA_API

///////////////////////////////////////////////////////////////////////////////
//
/// \file       index_decoder.c
/// \brief      Decodes the Index field
//
//  Author:     Lasse Collin
//
//  This file has been put into the public domain.
//  You can do whatever you want with this file.
//
///////////////////////////////////////////////////////////////////////////////

#include "index.h"
#include "check.h"


struct lzma_coder_s {
        enum {
                SEQ_INDICATOR,
                SEQ_COUNT,
                SEQ_MEMUSAGE,
                SEQ_UNPADDED,
                SEQ_UNCOMPRESSED,
                SEQ_PADDING_INIT,
                SEQ_PADDING,
                SEQ_CRC32,
        } sequence;

        /// Memory usage limit
        uint64_t memlimit;

        /// Target Index
        lzma_index *index;

        /// Pointer give by the application, which is set after
        /// successful decoding.
        lzma_index **index_ptr;

        /// Number of Records left to decode.
        lzma_vli count;

        /// The most recent Unpadded Size field
        lzma_vli unpadded_size;

        /// The most recent Uncompressed Size field
        lzma_vli uncompressed_size;

        /// Position in integers
        size_t pos;

        /// CRC32 of the List of Records field
        uint32_t crc32;
};


static lzma_ret
index_decode(lzma_coder *coder, lzma_allocator *allocator,
                const uint8_t *restrict in, size_t *restrict in_pos,
                size_t in_size,
                uint8_t *restrict out lzma_attribute((__unused__)),
                size_t *restrict out_pos lzma_attribute((__unused__)),
                size_t out_size lzma_attribute((__unused__)),
                lzma_action action lzma_attribute((__unused__)))
{
        // Similar optimization as in index_encoder.c
        const size_t in_start = *in_pos;
        lzma_ret ret = LZMA_OK;

        while (*in_pos < in_size)
        switch (coder->sequence) {
        case SEQ_INDICATOR:
                // Return LZMA_DATA_ERROR instead of e.g. LZMA_PROG_ERROR or
                // LZMA_FORMAT_ERROR, because a typical usage case for Index
                // decoder is when parsing the Stream backwards. If seeking
                // backward from the Stream Footer gives us something that
                // doesn't begin with Index Indicator, the file is considered
                // corrupt, not "programming error" or "unrecognized file
                // format". One could argue that the application should
                // verify the Index Indicator before trying to decode the
                // Index, but well, I suppose it is simpler this way.
                if (in[(*in_pos)++] != 0x00)
                        return LZMA_DATA_ERROR;

                coder->sequence = SEQ_COUNT;
                break;

        case SEQ_COUNT:
                ret = lzma_vli_decode(&coder->count, &coder->pos,
                                in, in_pos, in_size);
                if (ret != LZMA_STREAM_END)
                        goto out;

                coder->pos = 0;
                coder->sequence = SEQ_MEMUSAGE;

        // Fall through

        case SEQ_MEMUSAGE:
                if (lzma_index_memusage(1, coder->count) > coder->memlimit) {
                        ret = LZMA_MEMLIMIT_ERROR;
                        goto out;
                }

                // Tell the Index handling code how many Records this
                // Index has to allow it to allocate memory more efficiently.
                lzma_index_prealloc(coder->index, coder->count);

                ret = LZMA_OK;
                coder->sequence = coder->count == 0
                                ? SEQ_PADDING_INIT : SEQ_UNPADDED;
                break;

        case SEQ_UNPADDED:
        case SEQ_UNCOMPRESSED: {
                lzma_vli *size = coder->sequence == SEQ_UNPADDED
                                ? &coder->unpadded_size
                                : &coder->uncompressed_size;

                ret = lzma_vli_decode(size, &coder->pos,
                                in, in_pos, in_size);
                if (ret != LZMA_STREAM_END)
                        goto out;

                ret = LZMA_OK;
                coder->pos = 0;

                if (coder->sequence == SEQ_UNPADDED) {
                        // Validate that encoded Unpadded Size isn't too small
                        // or too big.
                        if (coder->unpadded_size < UNPADDED_SIZE_MIN
                                        || coder->unpadded_size
                                                > UNPADDED_SIZE_MAX)
                                return LZMA_DATA_ERROR;

                        coder->sequence = SEQ_UNCOMPRESSED;
                } else {
                        // Add the decoded Record to the Index.
                        return_if_error(lzma_index_append(
                                        coder->index, allocator,
                                        coder->unpadded_size,
                                        coder->uncompressed_size));

                        // Check if this was the last Record.
                        coder->sequence = --coder->count == 0
                                        ? SEQ_PADDING_INIT
                                        : SEQ_UNPADDED;
                }

                break;
        }

        case SEQ_PADDING_INIT:
                coder->pos = lzma_index_padding_size(coder->index);
                coder->sequence = SEQ_PADDING;

        // Fall through

        case SEQ_PADDING:
                if (coder->pos > 0) {
                        --coder->pos;
                        if (in[(*in_pos)++] != 0x00)
                                return LZMA_DATA_ERROR;

                        break;
                }

                // Finish the CRC32 calculation.
                coder->crc32 = lzma_crc32(in + in_start,
                                *in_pos - in_start, coder->crc32);

                coder->sequence = SEQ_CRC32;

        // Fall through

        case SEQ_CRC32:
                do {
                        if (*in_pos == in_size)
                                return LZMA_OK;

                        if (((coder->crc32 >> (coder->pos * 8)) & 0xFF)
                                        != in[(*in_pos)++])
                                return LZMA_DATA_ERROR;

                } while (++coder->pos < 4);

                // Decoding was successful, now we can let the application
                // see the decoded Index.
                *coder->index_ptr = coder->index;

                // Make index NULL so we don't free it unintentionally.
                coder->index = NULL;

                return LZMA_STREAM_END;

        default:
                assert(0);
                return LZMA_PROG_ERROR;
        }

out:
        // Update the CRC32,
        coder->crc32 = lzma_crc32(in + in_start,
                        *in_pos - in_start, coder->crc32);

        return ret;
}


static void
index_decoder_end(lzma_coder *coder, lzma_allocator *allocator)
{
        lzma_index_end(coder->index, allocator);
        lzma_free(coder, allocator);
        return;
}


static lzma_ret
index_decoder_memconfig(lzma_coder *coder, uint64_t *memusage,
                uint64_t *old_memlimit, uint64_t new_memlimit)
{
        *memusage = lzma_index_memusage(1, coder->count);
        *old_memlimit = coder->memlimit;

        if (new_memlimit != 0) {
                if (new_memlimit < *memusage)
                        return LZMA_MEMLIMIT_ERROR;

                coder->memlimit = new_memlimit;
        }

        return LZMA_OK;
}


static lzma_ret
index_decoder_reset(lzma_coder *coder, lzma_allocator *allocator,
                lzma_index **i, uint64_t memlimit)
{
        // Remember the pointer given by the application. We will set it
        // to point to the decoded Index only if decoding is successful.
        // Before that, keep it NULL so that applications can always safely
        // pass it to lzma_index_end() no matter did decoding succeed or not.
        coder->index_ptr = i;
        *i = NULL;

        // We always allocate a new lzma_index.
        coder->index = lzma_index_init(allocator);
        if (coder->index == NULL)
                return LZMA_MEM_ERROR;

        // Initialize the rest.
        coder->sequence = SEQ_INDICATOR;
        coder->memlimit = memlimit;
        coder->count = 0; // Needs to be initialized due to _memconfig().
        coder->pos = 0;
        coder->crc32 = 0;

        return LZMA_OK;
}


static lzma_ret
index_decoder_init(lzma_next_coder *next, lzma_allocator *allocator,
                lzma_index **i, uint64_t memlimit)
{
        lzma_next_coder_init(&index_decoder_init, next, allocator);

        if (i == NULL || memlimit == 0)
                return LZMA_PROG_ERROR;

        if (next->coder == NULL) {
                next->coder = lzma_alloc(sizeof(lzma_coder), allocator);
                if (next->coder == NULL)
                        return LZMA_MEM_ERROR;

                next->code = &index_decode;
                next->end = &index_decoder_end;
                next->memconfig = &index_decoder_memconfig;
                next->coder->index = NULL;
        } else {
                lzma_index_end(next->coder->index, allocator);
        }

        return index_decoder_reset(next->coder, allocator, i, memlimit);
}


extern LZMA_API(lzma_ret)
lzma_index_decoder(lzma_stream *strm, lzma_index **i, uint64_t memlimit)
{
        lzma_next_strm_init(index_decoder_init, strm, i, memlimit);

        strm->internal->supported_actions[LZMA_RUN] = true;
        strm->internal->supported_actions[LZMA_FINISH] = true;

        return LZMA_OK;
}


extern LZMA_API(lzma_ret)
lzma_index_buffer_decode(
                lzma_index **i, uint64_t *memlimit, lzma_allocator *allocator,
                const uint8_t *in, size_t *in_pos, size_t in_size)
{
        // Sanity checks
        if (i == NULL || memlimit == NULL
                        || in == NULL || in_pos == NULL || *in_pos > in_size)
                return LZMA_PROG_ERROR;

        // Initialize the decoder.
        lzma_coder coder;
        return_if_error(index_decoder_reset(&coder, allocator, i, *memlimit));

        // Store the input start position so that we can restore it in case
        // of an error.
        const size_t in_start = *in_pos;

        // Do the actual decoding.
        lzma_ret ret = index_decode(&coder, allocator, in, in_pos, in_size,
                        NULL, NULL, 0, LZMA_RUN);

        if (ret == LZMA_STREAM_END) {
                ret = LZMA_OK;
        } else {
                // Something went wrong, free the Index structure and restore
                // the input position.
                lzma_index_end(coder.index, allocator);
                *in_pos = in_start;

                if (ret == LZMA_OK) {
                        // The input is truncated or otherwise corrupt.
                        // Use LZMA_DATA_ERROR instead of LZMA_BUF_ERROR
                        // like lzma_vli_decode() does in single-call mode.
                        ret = LZMA_DATA_ERROR;

                } else if (ret == LZMA_MEMLIMIT_ERROR) {
                        // Tell the caller how much memory would have
                        // been needed.
                        *memlimit = lzma_index_memusage(1, coder.count);
                }
        }

        return ret;
}

/* [<][>][^][v][top][bottom][index][help] */