aboutsummaryrefslogtreecommitdiff
path: root/lib/comp/xz.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/comp/xz.c')
-rw-r--r--lib/comp/xz.c360
1 files changed, 0 insertions, 360 deletions
diff --git a/lib/comp/xz.c b/lib/comp/xz.c
deleted file mode 100644
index d38aab6..0000000
--- a/lib/comp/xz.c
+++ /dev/null
@@ -1,360 +0,0 @@
-/* SPDX-License-Identifier: GPL-3.0-or-later */
-/*
- * xz.c
- *
- * Copyright (C) 2019 David Oberhollenzer <goliath@infraroot.at>
- */
-#include "config.h"
-
-#include <stdbool.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdio.h>
-#include <ctype.h>
-#include <lzma.h>
-
-#include "internal.h"
-
-typedef enum {
- XZ_FILTER_X86 = 0x01,
- XZ_FILTER_POWERPC = 0x02,
- XZ_FILTER_IA64 = 0x04,
- XZ_FILTER_ARM = 0x08,
- XZ_FILTER_ARMTHUMB = 0x10,
- XZ_FILTER_SPARC = 0x20,
-
- XZ_FILTER_ALL = 0x3F,
-} XZ_FILTER_FLAG;
-
-typedef struct {
- compressor_t base;
- size_t block_size;
- size_t dict_size;
- int flags;
-} xz_compressor_t;
-
-typedef struct {
- uint32_t dict_size;
- uint32_t flags;
-} xz_options_t;
-
-static const struct {
- const char *name;
- lzma_vli filter;
- int flag;
-} xz_filters[] = {
- { "x86", LZMA_FILTER_X86, XZ_FILTER_X86 },
- { "powerpc", LZMA_FILTER_POWERPC, XZ_FILTER_POWERPC },
- { "ia64", LZMA_FILTER_IA64, XZ_FILTER_IA64 },
- { "arm", LZMA_FILTER_ARM, XZ_FILTER_ARM },
- { "armthumb", LZMA_FILTER_ARMTHUMB, XZ_FILTER_ARMTHUMB },
- { "sparc", LZMA_FILTER_SPARC, XZ_FILTER_SPARC },
-};
-
-#define XZ_NUM_FILTERS (sizeof(xz_filters) / sizeof(xz_filters[0]))
-
-static int xz_write_options(compressor_t *base, int fd)
-{
- xz_compressor_t *xz = (xz_compressor_t *)base;
- xz_options_t opt;
-
- if (xz->flags == 0 && xz->dict_size == xz->block_size)
- return 0;
-
- opt.dict_size = htole32(xz->dict_size);
- opt.flags = htole32(xz->flags);
-
- return generic_write_options(fd, &opt, sizeof(opt));
-}
-
-static int xz_read_options(compressor_t *base, int fd)
-{
- xz_compressor_t *xz = (xz_compressor_t *)base;
- xz_options_t opt;
- uint32_t mask;
-
- if (generic_read_options(fd, &opt, sizeof(opt)))
- return -1;
-
- opt.dict_size = le32toh(opt.dict_size);
- opt.flags = le32toh(opt.flags);
-
- mask = opt.dict_size & (opt.dict_size - 1);
-
- if (mask != 0 && ((mask & (mask - 1)) != 0)) {
- fputs("Invalid lzma dictionary size.\n", stderr);
- return -1;
- }
-
- if (opt.flags & ~XZ_FILTER_ALL) {
- fputs("Unknown BCJ filter used.\n", stderr);
- return -1;
- }
-
- xz->flags = opt.flags;
- xz->dict_size = opt.dict_size;
- return 0;
-}
-
-static ssize_t compress(xz_compressor_t *xz, lzma_vli filter,
- const uint8_t *in, size_t size,
- uint8_t *out, size_t outsize)
-{
- lzma_filter filters[5];
- lzma_options_lzma opt;
- size_t written = 0;
- lzma_ret ret;
- int i = 0;
-
- if (lzma_lzma_preset(&opt, LZMA_PRESET_DEFAULT)) {
- fputs("error initializing xz options\n", stderr);
- return -1;
- }
-
- opt.dict_size = xz->dict_size;
-
- if (filter != LZMA_VLI_UNKNOWN) {
- filters[i].id = filter;
- filters[i].options = NULL;
- ++i;
- }
-
- filters[i].id = LZMA_FILTER_LZMA2;
- filters[i].options = &opt;
- ++i;
-
- filters[i].id = LZMA_VLI_UNKNOWN;
- filters[i].options = NULL;
- ++i;
-
- ret = lzma_stream_buffer_encode(filters, LZMA_CHECK_CRC32, NULL,
- in, size, out, &written, outsize);
-
- if (ret == LZMA_OK)
- return (written >= size) ? 0 : written;
-
- if (ret != LZMA_BUF_ERROR) {
- fputs("xz block compress failed\n", stderr);
- return -1;
- }
-
- return 0;
-}
-
-static ssize_t xz_comp_block(compressor_t *base, const uint8_t *in,
- size_t size, uint8_t *out, size_t outsize)
-{
- xz_compressor_t *xz = (xz_compressor_t *)base;
- lzma_vli selected = LZMA_VLI_UNKNOWN;
- size_t i, smallest;
- ssize_t ret;
-
- ret = compress(xz, LZMA_VLI_UNKNOWN, in, size, out, outsize);
- if (ret < 0 || xz->flags == 0)
- return ret;
-
- smallest = ret;
-
- for (i = 0; i < XZ_NUM_FILTERS; ++i) {
- if (!(xz->flags & xz_filters[i].flag))
- continue;
-
- ret = compress(xz, xz_filters[i].filter, in, size, out, outsize);
- if (ret < 0)
- return -1;
-
- if (ret > 0 && (smallest == 0 || (size_t)ret < smallest)) {
- smallest = ret;
- selected = xz_filters[i].filter;
- }
- }
-
- if (smallest == 0)
- return 0;
-
- return compress(xz, selected, in, size, out, outsize);
-}
-
-static ssize_t xz_uncomp_block(compressor_t *base, const uint8_t *in,
- size_t size, uint8_t *out, size_t outsize)
-{
- uint64_t memlimit = 32 * 1024 * 1024;
- size_t dest_pos = 0;
- size_t src_pos = 0;
- lzma_ret ret;
- (void)base;
-
- ret = lzma_stream_buffer_decode(&memlimit, 0, NULL,
- in, &src_pos, size,
- out, &dest_pos, outsize);
-
- if (ret == LZMA_OK && size == src_pos)
- return (ssize_t)dest_pos;
-
- fputs("xz block extract failed\n", stderr);
- return -1;
-}
-
-static compressor_t *xz_create_copy(compressor_t *cmp)
-{
- xz_compressor_t *xz = malloc(sizeof(*xz));
-
- if (xz == NULL) {
- perror("creating additional xz compressor");
- return NULL;
- }
-
- memcpy(xz, cmp, sizeof(*xz));
- return (compressor_t *)xz;
-}
-
-static void xz_destroy(compressor_t *base)
-{
- free(base);
-}
-
-static int process_options(char *options, size_t blocksize,
- int *flags, uint64_t *dictsize)
-{
- enum {
- OPT_DICT = 0,
- };
- char *const token[] = {
- [OPT_DICT] = (char *)"dictsize",
- NULL
- };
- char *subopts, *value;
- uint64_t mask;
- size_t i;
- int opt;
-
- subopts = options;
-
- while (*subopts != '\0') {
- opt = getsubopt(&subopts, token, &value);
-
- switch (opt) {
- case OPT_DICT:
- if (value == NULL)
- goto fail_value;
-
- for (i = 0; isdigit(value[i]); ++i)
- ;
-
- if (i < 1 || i > 9)
- goto fail_dict;
-
- *dictsize = atol(value);
-
- switch (value[i]) {
- case '\0':
- break;
- case 'm':
- case 'M':
- *dictsize <<= 20;
- break;
- case 'k':
- case 'K':
- *dictsize <<= 10;
- break;
- case '%':
- *dictsize = ((*dictsize) * blocksize) / 100;
- break;
- default:
- goto fail_dict;
- }
-
- if (*dictsize > 0x0FFFFFFFFUL)
- goto fail_dict_ov;
-
- mask = *dictsize & (*dictsize - 1);
-
- if (mask != 0 && ((mask & (mask - 1)) != 0))
- goto fail_dict_pot;
- break;
- default:
- for (i = 0; i < XZ_NUM_FILTERS; ++i) {
- if (strcmp(value, xz_filters[i].name) == 0) {
- *flags |= xz_filters[i].flag;
- break;
- }
- }
- if (i == XZ_NUM_FILTERS)
- goto fail_opt;
- break;
- }
- }
-
- return 0;
-fail_dict_pot:
- fputs("dictionary size must be either 2^n or 2^n + 2^(n-1)\n", stderr);
- return -1;
-fail_dict_ov:
- fputs("dictionary size too large.\n", stderr);
- return -1;
-fail_dict:
- fputs("dictionary size must be a number with the optional "
- "suffix 'm','k' or '%'.\n", stderr);
- return -1;
-fail_opt:
- fprintf(stderr, "Unknown option '%s'.\n", value);
- return -1;
-fail_value:
- fprintf(stderr, "Missing value for '%s'.\n", token[opt]);
- return -1;
-}
-
-compressor_t *create_xz_compressor(bool compress, size_t block_size,
- char *options)
-{
- uint64_t dictsize = block_size;
- xz_compressor_t *xz;
- compressor_t *base;
- int flags = 0;
-
- if (options != NULL) {
- if (process_options(options, block_size, &flags, &dictsize))
- return NULL;
- }
-
- xz = calloc(1, sizeof(*xz));
- base = (compressor_t *)xz;
- if (xz == NULL) {
- perror("creating xz compressor");
- return NULL;
- }
-
- xz->flags = flags;
- xz->dict_size = dictsize;
- xz->block_size = block_size;
- base->destroy = xz_destroy;
- base->do_block = compress ? xz_comp_block : xz_uncomp_block;
- base->write_options = xz_write_options;
- base->read_options = xz_read_options;
- base->create_copy = xz_create_copy;
- return base;
-}
-
-void compressor_xz_print_help(void)
-{
- size_t i;
-
- fputs(
-"Available options for xz compressor:\n"
-"\n"
-" dictsize=<value> Dictionary size. Either a value in bytes or a\n"
-" percentage of the block size. Defaults to 100%.\n"
-" The suffix '%' indicates a percentage. 'K' and 'M'\n"
-" can also be used for kibi and mebi bytes\n"
-" respecitively.\n"
-"\n"
-"In additon to the options, one or more bcj filters can be specified.\n"
-"If multiple filters are provided, the one yielding the best compression\n"
-"ratio will be used.\n"
-"\n"
-"The following filters are available:\n",
- stdout);
-
- for (i = 0; i < XZ_NUM_FILTERS; ++i)
- printf("\t%s\n", xz_filters[i].name);
-}