xref: /aosp_15_r20/external/coreboot/util/cbfstool/lzma/lzma.c (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
1 #include <stdio.h>
2 #include <stdint.h>
3 #include <stdlib.h>
4 #include <string.h>
5 #include "../common.h"
6 #include "C/LzmaDec.h"
7 #include "C/LzmaEnc.h"
8 
9 #define L (uint64_t)
10 
get_64(const void * p)11 static inline uint64_t get_64(const void *p)
12 {
13 	const unsigned char *data = (const unsigned char *)p;
14 	return (L data[0]) | (L data[1] << 8) | (L data[2] << 16) |
15 		(L data[3] << 24) | (L data [4] << 32) | (L data[5] << 40) |
16 		(L data[6] << 48) | (L data[7] << 56);
17 }
18 
put_64(void * p,uint64_t value)19 static void put_64(void *p, uint64_t value)
20 {
21 	unsigned char *data = (unsigned char *)p;
22 	data[0] = value & 0xff;
23 	data[1] = (value >> 8) & 0xff;
24 	data[2] = (value >> 16) & 0xff;
25 	data[3] = (value >> 24) & 0xff;
26 	data[4] = (value >> 32) & 0xff;
27 	data[5] = (value >> 40) & 0xff;
28 	data[6] = (value >> 48) & 0xff;
29 	data[7] = (value >> 56) & 0xff;
30 }
31 
32 /* Memory Allocation API */
33 
SzAlloc(unused void * u,size_t size)34 static void *SzAlloc(unused void *u, size_t size)
35 {
36 	return malloc(size);
37 }
38 
SzFree(unused void * u,void * address)39 static void SzFree(unused void *u, void *address)
40 {
41 	free(address);
42 }
43 
44 static struct ISzAlloc LZMAalloc = { SzAlloc, SzFree };
45 
46 /* Streaming API */
47 
48 struct vector_t {
49 	char *p;
50 	size_t pos;
51 	size_t size;
52 };
53 
54 static struct vector_t instream, outstream;
55 
Read(unused void * u,void * buf,size_t * size)56 static SRes Read(unused void *u, void *buf, size_t *size)
57 {
58 	if ((instream.size - instream.pos) < *size)
59 		*size = instream.size - instream.pos;
60 	memcpy(buf, instream.p + instream.pos, *size);
61 	instream.pos += *size;
62 	return SZ_OK;
63 }
64 
Write(unused void * u,const void * buf,size_t size)65 static size_t Write(unused void *u, const void *buf, size_t size)
66 {
67 	if(outstream.size - outstream.pos < size)
68 		size = outstream.size - outstream.pos;
69 	memcpy(outstream.p + outstream.pos, buf, size);
70 	outstream.pos += size;
71 	return size;
72 }
73 
74 static struct ISeqInStream is = { Read };
75 static struct ISeqOutStream os = { Write };
76 
77 /**
78  * Compress a buffer with lzma
79  * Don't copy the result back if it is too large.
80  * @param in a pointer to the buffer
81  * @param in_len the length in bytes
82  * @param out a pointer to a buffer of at least size in_len
83  * @param out_len a pointer to the compressed length of in
84  */
85 
do_lzma_compress(char * in,int in_len,char * out,int * out_len)86 int do_lzma_compress(char *in, int in_len, char *out, int *out_len)
87 {
88 	if (in_len == 0) {
89 		ERROR("LZMA: Input length is zero.\n");
90 		return -1;
91 	}
92 
93 	struct CLzmaEncProps props;
94 	LzmaEncProps_Init(&props);
95 	props.dictSize = in_len;
96 	props.pb = 0; /* PosStateBits, default: 2, range: 0..4 */
97 	props.lp = 0; /* LiteralPosStateBits, default: 0, range: 0..4 */
98 	props.lc = 1; /* LiteralContextBits, default: 3, range: 0..8 */
99 	props.fb = 273; /* NumFastBytes */
100 	props.mc = 0; /* MatchFinderCycles, default: 0 */
101 	props.algo = 1; /* AlgorithmNo, apparently, 0 and 1 are valid values. 0 = fast mode */
102 	props.numThreads = 1;
103 
104 	switch (props.algo) {
105 	case 0:	// quick: HC4
106 		props.btMode = 0;
107 		props.level = 1;
108 		break;
109 	case 1:	// full: BT4
110 	default:
111 		props.level = 9;
112 		props.btMode = 1;
113 		props.numHashBytes = 4;
114 		break;
115 	}
116 
117 	CLzmaEncHandle p = LzmaEnc_Create(&LZMAalloc);
118 
119 	int res = LzmaEnc_SetProps(p, &props);
120 	if (res != SZ_OK) {
121 		ERROR("LZMA: LzmaEnc_SetProps failed.\n");
122 		return -1;
123 	}
124 
125 	unsigned char propsEncoded[LZMA_PROPS_SIZE + 8];
126 	size_t propsSize = sizeof propsEncoded;
127 	res = LzmaEnc_WriteProperties(p, propsEncoded, &propsSize);
128 	if (res != SZ_OK) {
129 		ERROR("LZMA: LzmaEnc_WriteProperties failed.\n");
130 		return -1;
131 	}
132 
133 	instream.p = in;
134 	instream.pos = 0;
135 	instream.size = in_len;
136 
137 	outstream.p = out;
138 	outstream.pos = 0;
139 	outstream.size = in_len;
140 
141 	put_64(propsEncoded + LZMA_PROPS_SIZE, in_len);
142 	Write(&os, propsEncoded, LZMA_PROPS_SIZE+8);
143 
144 	res = LzmaEnc_Encode(p, &os, &is, 0, &LZMAalloc, &LZMAalloc);
145 	LzmaEnc_Destroy(p, &LZMAalloc, &LZMAalloc);
146 	if (res != SZ_OK) {
147 		ERROR("LZMA: LzmaEnc_Encode failed %d.\n", res);
148 		return -1;
149 	}
150 
151 	*out_len = outstream.pos;
152 	return 0;
153 }
154 
do_lzma_uncompress(char * dst,int dst_len,char * src,int src_len,size_t * actual_size)155 int do_lzma_uncompress(char *dst, int dst_len, char *src, int src_len,
156 			size_t *actual_size)
157 {
158 	if (src_len <= LZMA_PROPS_SIZE + 8) {
159 		ERROR("LZMA: Input length is too small.\n");
160 		return -1;
161 	}
162 
163 	uint64_t out_sizemax = get_64(&src[LZMA_PROPS_SIZE]);
164 
165 	if (out_sizemax > (size_t) dst_len) {
166 		ERROR("Not copying %d bytes to %d-byte buffer!\n",
167 			(unsigned int)out_sizemax, dst_len);
168 		return -1;
169 	}
170 
171 	enum ELzmaStatus status;
172 
173 	size_t destlen = out_sizemax;
174 	size_t srclen = src_len - (LZMA_PROPS_SIZE + 8);
175 
176 	int res = LzmaDecode((uint8_t *) dst, &destlen,
177 			     (uint8_t *) &src[LZMA_PROPS_SIZE + 8], &srclen,
178 			     (uint8_t *) &src[0], LZMA_PROPS_SIZE,
179 			     LZMA_FINISH_END,
180 			     &status,
181 			     &LZMAalloc);
182 
183 	if (res != SZ_OK) {
184 		ERROR("Error while decompressing.\n");
185 		return -1;
186 	}
187 
188 	if (actual_size != NULL)
189 		*actual_size = destlen;
190 
191 	return 0;
192 }
193