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