xref: /aosp_15_r20/external/erofs-utils/lib/compressor_liblzma.c (revision 33b1fccf6a0fada2c2875d400ed01119b7676ee5)
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