root/tests/test_block_header.c

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

DEFINITIONS

This source file includes following definitions.
  1. code
  2. test1
  3. test2
  4. test3
  5. main

///////////////////////////////////////////////////////////////////////////////
//
/// \file       test_block_header.c
/// \brief      Tests Block Header coders
//
//  Author:     Lasse Collin
//
//  This file has been put into the public domain.
//  You can do whatever you want with this file.
//
///////////////////////////////////////////////////////////////////////////////

#include "tests.h"


static uint8_t buf[LZMA_BLOCK_HEADER_SIZE_MAX];
static lzma_block known_options;
static lzma_block decoded_options;

static lzma_options_lzma opt_lzma;

static lzma_filter filters_none[1] = {
        {
                .id = LZMA_VLI_UNKNOWN,
        },
};


static lzma_filter filters_one[2] = {
        {
                .id = LZMA_FILTER_LZMA2,
                .options = &opt_lzma,
        }, {
                .id = LZMA_VLI_UNKNOWN,
        }
};


static lzma_filter filters_four[5] = {
        {
                .id = LZMA_FILTER_X86,
                .options = NULL,
        }, {
                .id = LZMA_FILTER_X86,
                .options = NULL,
        }, {
                .id = LZMA_FILTER_X86,
                .options = NULL,
        }, {
                .id = LZMA_FILTER_LZMA2,
                .options = &opt_lzma,
        }, {
                .id = LZMA_VLI_UNKNOWN,
        }
};


static lzma_filter filters_five[6] = {
        {
                .id = LZMA_FILTER_X86,
                .options = NULL,
        }, {
                .id = LZMA_FILTER_X86,
                .options = NULL,
        }, {
                .id = LZMA_FILTER_X86,
                .options = NULL,
        }, {
                .id = LZMA_FILTER_X86,
                .options = NULL,
        }, {
                .id = LZMA_FILTER_LZMA2,
                .options = &opt_lzma,
        }, {
                .id = LZMA_VLI_UNKNOWN,
        }
};


static void
code(void)
{
        expect(lzma_block_header_encode(&known_options, buf) == LZMA_OK);

        lzma_filter filters[LZMA_FILTERS_MAX + 1];
        memcrap(filters, sizeof(filters));
        memcrap(&decoded_options, sizeof(decoded_options));

        decoded_options.header_size = known_options.header_size;
        decoded_options.check = known_options.check;
        decoded_options.filters = filters;
        expect(lzma_block_header_decode(&decoded_options, NULL, buf)
                        == LZMA_OK);

        expect(known_options.compressed_size
                        == decoded_options.compressed_size);
        expect(known_options.uncompressed_size
                        == decoded_options.uncompressed_size);

        for (size_t i = 0; known_options.filters[i].id
                        != LZMA_VLI_UNKNOWN; ++i)
                expect(known_options.filters[i].id == filters[i].id);

        for (size_t i = 0; i < LZMA_FILTERS_MAX; ++i)
                free(decoded_options.filters[i].options);
}


static void
test1(void)
{
        known_options = (lzma_block){
                .check = LZMA_CHECK_NONE,
                .compressed_size = LZMA_VLI_UNKNOWN,
                .uncompressed_size = LZMA_VLI_UNKNOWN,
                .filters = NULL,
        };

        expect(lzma_block_header_size(&known_options) == LZMA_PROG_ERROR);

        known_options.filters = filters_none;
        expect(lzma_block_header_size(&known_options) == LZMA_PROG_ERROR);

        known_options.filters = filters_five;
        expect(lzma_block_header_size(&known_options) == LZMA_PROG_ERROR);

        known_options.filters = filters_one;
        expect(lzma_block_header_size(&known_options) == LZMA_OK);

        known_options.check = 999; // Some invalid value, which gets ignored.
        expect(lzma_block_header_size(&known_options) == LZMA_OK);

        known_options.compressed_size = 5;
        expect(lzma_block_header_size(&known_options) == LZMA_OK);

        known_options.compressed_size = 0; // Cannot be zero.
        expect(lzma_block_header_size(&known_options) == LZMA_PROG_ERROR);

        // LZMA_VLI_MAX is too big to keep the total size of the Block
        // a valid VLI, but lzma_block_header_size() is not meant
        // to validate it. (lzma_block_header_encode() must validate it.)
        known_options.compressed_size = LZMA_VLI_MAX;
        expect(lzma_block_header_size(&known_options) == LZMA_OK);

        known_options.compressed_size = LZMA_VLI_UNKNOWN;
        known_options.uncompressed_size = 0;
        expect(lzma_block_header_size(&known_options) == LZMA_OK);

        known_options.uncompressed_size = LZMA_VLI_MAX + 1;
        expect(lzma_block_header_size(&known_options) == LZMA_PROG_ERROR);
}


static void
test2(void)
{
        known_options = (lzma_block){
                .check = LZMA_CHECK_CRC32,
                .compressed_size = LZMA_VLI_UNKNOWN,
                .uncompressed_size = LZMA_VLI_UNKNOWN,
                .filters = filters_four,
        };

        expect(lzma_block_header_size(&known_options) == LZMA_OK);
        code();

        known_options.compressed_size = 123456;
        known_options.uncompressed_size = 234567;
        expect(lzma_block_header_size(&known_options) == LZMA_OK);
        code();

        // We can make the sizes smaller while keeping the header size
        // the same.
        known_options.compressed_size = 12;
        known_options.uncompressed_size = 23;
        code();
}


static void
test3(void)
{
        known_options = (lzma_block){
                .check = LZMA_CHECK_CRC32,
                .compressed_size = LZMA_VLI_UNKNOWN,
                .uncompressed_size = LZMA_VLI_UNKNOWN,
                .filters = filters_one,
        };

        expect(lzma_block_header_size(&known_options) == LZMA_OK);
        known_options.header_size += 4;
        expect(lzma_block_header_encode(&known_options, buf) == LZMA_OK);

        lzma_filter filters[LZMA_FILTERS_MAX + 1];
        decoded_options.header_size = known_options.header_size;
        decoded_options.check = known_options.check;
        decoded_options.filters = filters;

        // Wrong size
        ++buf[0];
        expect(lzma_block_header_decode(&decoded_options, NULL, buf)
                        == LZMA_PROG_ERROR);
        --buf[0];

        // Wrong CRC32
        buf[known_options.header_size - 1] ^= 1;
        expect(lzma_block_header_decode(&decoded_options, NULL, buf)
                        == LZMA_DATA_ERROR);
        buf[known_options.header_size - 1] ^= 1;

        // Unsupported filter
        // NOTE: This may need updating when new IDs become supported.
        buf[2] ^= 0x1F;
        unaligned_write32le(buf + known_options.header_size - 4,
                        lzma_crc32(buf, known_options.header_size - 4, 0));
        expect(lzma_block_header_decode(&decoded_options, NULL, buf)
                        == LZMA_OPTIONS_ERROR);
        buf[2] ^= 0x1F;

        // Non-nul Padding
        buf[known_options.header_size - 4 - 1] ^= 1;
        unaligned_write32le(buf + known_options.header_size - 4,
                        lzma_crc32(buf, known_options.header_size - 4, 0));
        expect(lzma_block_header_decode(&decoded_options, NULL, buf)
                        == LZMA_OPTIONS_ERROR);
        buf[known_options.header_size - 4 - 1] ^= 1;
}


int
main(void)
{
        succeed(lzma_lzma_preset(&opt_lzma, 1));

        test1();
        test2();
        test3();

        return 0;
}

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