1*33b1fccfSAndroid Build Coastguard Worker // SPDX-License-Identifier: GPL-2.0+ OR Apache-2.0
2*33b1fccfSAndroid Build Coastguard Worker /*
3*33b1fccfSAndroid Build Coastguard Worker * Copyright (C) 2021 Gao Xiang <[email protected]>
4*33b1fccfSAndroid Build Coastguard Worker */
5*33b1fccfSAndroid Build Coastguard Worker #include <stdlib.h>
6*33b1fccfSAndroid Build Coastguard Worker #include "config.h"
7*33b1fccfSAndroid Build Coastguard Worker #ifdef HAVE_LIBLZMA
8*33b1fccfSAndroid Build Coastguard Worker #include <lzma.h>
9*33b1fccfSAndroid Build Coastguard Worker #include "erofs/config.h"
10*33b1fccfSAndroid Build Coastguard Worker #include "erofs/print.h"
11*33b1fccfSAndroid Build Coastguard Worker #include "erofs/internal.h"
12*33b1fccfSAndroid Build Coastguard Worker #include "erofs/atomic.h"
13*33b1fccfSAndroid Build Coastguard Worker #include "compressor.h"
14*33b1fccfSAndroid Build Coastguard Worker
15*33b1fccfSAndroid Build Coastguard Worker struct erofs_liblzma_context {
16*33b1fccfSAndroid Build Coastguard Worker lzma_options_lzma opt;
17*33b1fccfSAndroid Build Coastguard Worker lzma_stream strm;
18*33b1fccfSAndroid Build Coastguard Worker };
19*33b1fccfSAndroid Build Coastguard Worker
erofs_liblzma_compress_destsize(const struct erofs_compress * c,const void * src,unsigned int * srcsize,void * dst,unsigned int dstsize)20*33b1fccfSAndroid Build Coastguard Worker static int erofs_liblzma_compress_destsize(const struct erofs_compress *c,
21*33b1fccfSAndroid Build Coastguard Worker const void *src, unsigned int *srcsize,
22*33b1fccfSAndroid Build Coastguard Worker void *dst, unsigned int dstsize)
23*33b1fccfSAndroid Build Coastguard Worker {
24*33b1fccfSAndroid Build Coastguard Worker struct erofs_liblzma_context *ctx = c->private_data;
25*33b1fccfSAndroid Build Coastguard Worker lzma_stream *strm = &ctx->strm;
26*33b1fccfSAndroid Build Coastguard Worker
27*33b1fccfSAndroid Build Coastguard Worker lzma_ret ret = lzma_microlzma_encoder(strm, &ctx->opt);
28*33b1fccfSAndroid Build Coastguard Worker if (ret != LZMA_OK)
29*33b1fccfSAndroid Build Coastguard Worker return -EFAULT;
30*33b1fccfSAndroid Build Coastguard Worker
31*33b1fccfSAndroid Build Coastguard Worker strm->next_in = src;
32*33b1fccfSAndroid Build Coastguard Worker strm->avail_in = *srcsize;
33*33b1fccfSAndroid Build Coastguard Worker strm->next_out = dst;
34*33b1fccfSAndroid Build Coastguard Worker strm->avail_out = dstsize;
35*33b1fccfSAndroid Build Coastguard Worker
36*33b1fccfSAndroid Build Coastguard Worker ret = lzma_code(strm, LZMA_FINISH);
37*33b1fccfSAndroid Build Coastguard Worker if (ret != LZMA_STREAM_END)
38*33b1fccfSAndroid Build Coastguard Worker return -EBADMSG;
39*33b1fccfSAndroid Build Coastguard Worker
40*33b1fccfSAndroid Build Coastguard Worker *srcsize = strm->total_in;
41*33b1fccfSAndroid Build Coastguard Worker return strm->total_out;
42*33b1fccfSAndroid Build Coastguard Worker }
43*33b1fccfSAndroid Build Coastguard Worker
erofs_compressor_liblzma_exit(struct erofs_compress * c)44*33b1fccfSAndroid Build Coastguard Worker static int erofs_compressor_liblzma_exit(struct erofs_compress *c)
45*33b1fccfSAndroid Build Coastguard Worker {
46*33b1fccfSAndroid Build Coastguard Worker struct erofs_liblzma_context *ctx = c->private_data;
47*33b1fccfSAndroid Build Coastguard Worker
48*33b1fccfSAndroid Build Coastguard Worker if (!ctx)
49*33b1fccfSAndroid Build Coastguard Worker return -EINVAL;
50*33b1fccfSAndroid Build Coastguard Worker
51*33b1fccfSAndroid Build Coastguard Worker lzma_end(&ctx->strm);
52*33b1fccfSAndroid Build Coastguard Worker free(ctx);
53*33b1fccfSAndroid Build Coastguard Worker return 0;
54*33b1fccfSAndroid Build Coastguard Worker }
55*33b1fccfSAndroid Build Coastguard Worker
erofs_compressor_liblzma_setlevel(struct erofs_compress * c,int compression_level)56*33b1fccfSAndroid Build Coastguard Worker static int erofs_compressor_liblzma_setlevel(struct erofs_compress *c,
57*33b1fccfSAndroid Build Coastguard Worker int compression_level)
58*33b1fccfSAndroid Build Coastguard Worker {
59*33b1fccfSAndroid Build Coastguard Worker if (compression_level < 0)
60*33b1fccfSAndroid Build Coastguard Worker compression_level = erofs_compressor_lzma.default_level;
61*33b1fccfSAndroid Build Coastguard Worker
62*33b1fccfSAndroid Build Coastguard Worker if (compression_level > erofs_compressor_lzma.best_level) {
63*33b1fccfSAndroid Build Coastguard Worker erofs_err("invalid compression level %d", compression_level);
64*33b1fccfSAndroid Build Coastguard Worker return -EINVAL;
65*33b1fccfSAndroid Build Coastguard Worker }
66*33b1fccfSAndroid Build Coastguard Worker c->compression_level = compression_level;
67*33b1fccfSAndroid Build Coastguard Worker return 0;
68*33b1fccfSAndroid Build Coastguard Worker }
69*33b1fccfSAndroid Build Coastguard Worker
erofs_compressor_liblzma_setdictsize(struct erofs_compress * c,u32 dict_size)70*33b1fccfSAndroid Build Coastguard Worker static int erofs_compressor_liblzma_setdictsize(struct erofs_compress *c,
71*33b1fccfSAndroid Build Coastguard Worker u32 dict_size)
72*33b1fccfSAndroid Build Coastguard Worker {
73*33b1fccfSAndroid Build Coastguard Worker if (!dict_size) {
74*33b1fccfSAndroid Build Coastguard Worker if (erofs_compressor_lzma.default_dictsize) {
75*33b1fccfSAndroid Build Coastguard Worker dict_size = erofs_compressor_lzma.default_dictsize;
76*33b1fccfSAndroid Build Coastguard Worker } else {
77*33b1fccfSAndroid Build Coastguard Worker dict_size = min_t(u32, Z_EROFS_LZMA_MAX_DICT_SIZE,
78*33b1fccfSAndroid Build Coastguard Worker cfg.c_mkfs_pclustersize_max << 3);
79*33b1fccfSAndroid Build Coastguard Worker if (dict_size < 32768)
80*33b1fccfSAndroid Build Coastguard Worker dict_size = 32768;
81*33b1fccfSAndroid Build Coastguard Worker }
82*33b1fccfSAndroid Build Coastguard Worker }
83*33b1fccfSAndroid Build Coastguard Worker
84*33b1fccfSAndroid Build Coastguard Worker if (dict_size > Z_EROFS_LZMA_MAX_DICT_SIZE || dict_size < 4096) {
85*33b1fccfSAndroid Build Coastguard Worker erofs_err("invalid dictionary size %u", dict_size);
86*33b1fccfSAndroid Build Coastguard Worker return -EINVAL;
87*33b1fccfSAndroid Build Coastguard Worker }
88*33b1fccfSAndroid Build Coastguard Worker c->dict_size = dict_size;
89*33b1fccfSAndroid Build Coastguard Worker return 0;
90*33b1fccfSAndroid Build Coastguard Worker }
91*33b1fccfSAndroid Build Coastguard Worker
erofs_compressor_liblzma_init(struct erofs_compress * c)92*33b1fccfSAndroid Build Coastguard Worker static int erofs_compressor_liblzma_init(struct erofs_compress *c)
93*33b1fccfSAndroid Build Coastguard Worker {
94*33b1fccfSAndroid Build Coastguard Worker struct erofs_liblzma_context *ctx;
95*33b1fccfSAndroid Build Coastguard Worker u32 preset;
96*33b1fccfSAndroid Build Coastguard Worker
97*33b1fccfSAndroid Build Coastguard Worker ctx = malloc(sizeof(*ctx));
98*33b1fccfSAndroid Build Coastguard Worker if (!ctx)
99*33b1fccfSAndroid Build Coastguard Worker return -ENOMEM;
100*33b1fccfSAndroid Build Coastguard Worker ctx->strm = (lzma_stream)LZMA_STREAM_INIT;
101*33b1fccfSAndroid Build Coastguard Worker
102*33b1fccfSAndroid Build Coastguard Worker if (c->compression_level < 0)
103*33b1fccfSAndroid Build Coastguard Worker preset = LZMA_PRESET_DEFAULT;
104*33b1fccfSAndroid Build Coastguard Worker else if (c->compression_level >= 100)
105*33b1fccfSAndroid Build Coastguard Worker preset = (c->compression_level - 100) | LZMA_PRESET_EXTREME;
106*33b1fccfSAndroid Build Coastguard Worker else
107*33b1fccfSAndroid Build Coastguard Worker preset = c->compression_level;
108*33b1fccfSAndroid Build Coastguard Worker
109*33b1fccfSAndroid Build Coastguard Worker if (lzma_lzma_preset(&ctx->opt, preset))
110*33b1fccfSAndroid Build Coastguard Worker return -EINVAL;
111*33b1fccfSAndroid Build Coastguard Worker ctx->opt.dict_size = c->dict_size;
112*33b1fccfSAndroid Build Coastguard Worker
113*33b1fccfSAndroid Build Coastguard Worker c->private_data = ctx;
114*33b1fccfSAndroid Build Coastguard Worker return 0;
115*33b1fccfSAndroid Build Coastguard Worker }
116*33b1fccfSAndroid Build Coastguard Worker
117*33b1fccfSAndroid Build Coastguard Worker const struct erofs_compressor erofs_compressor_lzma = {
118*33b1fccfSAndroid Build Coastguard Worker .default_level = LZMA_PRESET_DEFAULT,
119*33b1fccfSAndroid Build Coastguard Worker .best_level = 109,
120*33b1fccfSAndroid Build Coastguard Worker .max_dictsize = Z_EROFS_LZMA_MAX_DICT_SIZE,
121*33b1fccfSAndroid Build Coastguard Worker .init = erofs_compressor_liblzma_init,
122*33b1fccfSAndroid Build Coastguard Worker .exit = erofs_compressor_liblzma_exit,
123*33b1fccfSAndroid Build Coastguard Worker .setlevel = erofs_compressor_liblzma_setlevel,
124*33b1fccfSAndroid Build Coastguard Worker .setdictsize = erofs_compressor_liblzma_setdictsize,
125*33b1fccfSAndroid Build Coastguard Worker .compress_destsize = erofs_liblzma_compress_destsize,
126*33b1fccfSAndroid Build Coastguard Worker };
127*33b1fccfSAndroid Build Coastguard Worker #endif
128