blob: 986ebfaa2217c105d599b29ead25b7aeb3742843 [file] [log] [blame]
Stefan Reinaueraa3f7ba2013-03-28 16:51:45 -07001#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
Stefan Reinaueraa3f7ba2013-03-28 16:51:45 -07009#define L (uint64_t)
10
11static inline uint64_t get_64(const void *p)
12{
Stefan Reinaueraa3f7ba2013-03-28 16:51:45 -070013 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);
Stefan Reinaueraa3f7ba2013-03-28 16:51:45 -070017}
18
19static void put_64(void *p, uint64_t value)
20{
Stefan Reinaueraa3f7ba2013-03-28 16:51:45 -070021 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;
Stefan Reinaueraa3f7ba2013-03-28 16:51:45 -070030}
31
32/* Memory Allocation API */
33
Stefan Reinauer2dd161f2015-03-04 00:55:03 +010034static void *SzAlloc(unused void *u, size_t size)
Stefan Reinaueraa3f7ba2013-03-28 16:51:45 -070035{
36 return malloc(size);
37}
38
Stefan Reinauer2dd161f2015-03-04 00:55:03 +010039static void SzFree(unused void *u, void *address)
Stefan Reinaueraa3f7ba2013-03-28 16:51:45 -070040{
41 free(address);
42}
43
Alexandru Gagniuc9ad52fe2014-01-27 20:57:54 -060044static struct ISzAlloc LZMAalloc = { SzAlloc, SzFree };
Stefan Reinaueraa3f7ba2013-03-28 16:51:45 -070045
46/* Streaming API */
47
Alexandru Gagniuc9ad52fe2014-01-27 20:57:54 -060048struct vector_t {
Stefan Reinaueraa3f7ba2013-03-28 16:51:45 -070049 char *p;
50 size_t pos;
51 size_t size;
Alexandru Gagniuc9ad52fe2014-01-27 20:57:54 -060052};
Stefan Reinaueraa3f7ba2013-03-28 16:51:45 -070053
Alexandru Gagniuc9ad52fe2014-01-27 20:57:54 -060054static struct vector_t instream, outstream;
Stefan Reinaueraa3f7ba2013-03-28 16:51:45 -070055
Stefan Reinauer2dd161f2015-03-04 00:55:03 +010056static SRes Read(unused void *u, void *buf, size_t *size)
Stefan Reinaueraa3f7ba2013-03-28 16:51:45 -070057{
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
Stefan Reinauer2dd161f2015-03-04 00:55:03 +010065static size_t Write(unused void *u, const void *buf, size_t size)
Stefan Reinaueraa3f7ba2013-03-28 16:51:45 -070066{
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
Alexandru Gagniuc9ad52fe2014-01-27 20:57:54 -060074static struct ISeqInStream is = { Read };
75static struct ISeqOutStream os = { Write };
Stefan Reinaueraa3f7ba2013-03-28 16:51:45 -070076
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
Gabe Blackdbd006b2014-02-20 23:38:49 -080086int do_lzma_compress(char *in, int in_len, char *out, int *out_len)
Stefan Reinaueraa3f7ba2013-03-28 16:51:45 -070087{
88 if (in_len == 0) {
89 ERROR("LZMA: Input length is zero.\n");
Gabe Blackdbd006b2014-02-20 23:38:49 -080090 return -1;
Stefan Reinaueraa3f7ba2013-03-28 16:51:45 -070091 }
92
Alexandru Gagniuc9ad52fe2014-01-27 20:57:54 -060093 struct CLzmaEncProps props;
Stefan Reinaueraa3f7ba2013-03-28 16:51:45 -070094 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");
Gabe Blackdbd006b2014-02-20 23:38:49 -0800122 return -1;
Stefan Reinaueraa3f7ba2013-03-28 16:51:45 -0700123 }
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");
Gabe Blackdbd006b2014-02-20 23:38:49 -0800130 return -1;
Stefan Reinaueraa3f7ba2013-03-28 16:51:45 -0700131 }
132
133 instream.p = in;
Stefan Reinauer33e83ca2013-04-08 11:20:55 -0700134 instream.pos = 0;
Stefan Reinaueraa3f7ba2013-03-28 16:51:45 -0700135 instream.size = in_len;
136
137 outstream.p = out;
Stefan Reinauer33e83ca2013-04-08 11:20:55 -0700138 outstream.pos = 0;
Stefan Reinaueraa3f7ba2013-03-28 16:51:45 -0700139 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);
Sol Boucher0e539312015-03-05 15:38:03 -0800145 LzmaEnc_Destroy(p, &LZMAalloc, &LZMAalloc);
Stefan Reinaueraa3f7ba2013-03-28 16:51:45 -0700146 if (res != SZ_OK) {
147 ERROR("LZMA: LzmaEnc_Encode failed %d.\n", res);
Gabe Blackdbd006b2014-02-20 23:38:49 -0800148 return -1;
Stefan Reinaueraa3f7ba2013-03-28 16:51:45 -0700149 }
150
151 *out_len = outstream.pos;
Gabe Blackdbd006b2014-02-20 23:38:49 -0800152 return 0;
Stefan Reinaueraa3f7ba2013-03-28 16:51:45 -0700153}
154
Aaron Durbin5213c532015-10-23 17:38:40 -0500155int do_lzma_uncompress(char *dst, int dst_len, char *src, int src_len,
156 size_t *actual_size)
Stefan Reinaueraa3f7ba2013-03-28 16:51:45 -0700157{
158 if (src_len <= LZMA_PROPS_SIZE + 8) {
159 ERROR("LZMA: Input length is too small.\n");
Gabe Blackdbd006b2014-02-20 23:38:49 -0800160 return -1;
Stefan Reinaueraa3f7ba2013-03-28 16:51:45 -0700161 }
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);
Gabe Blackdbd006b2014-02-20 23:38:49 -0800168 return -1;
Stefan Reinaueraa3f7ba2013-03-28 16:51:45 -0700169 }
170
Alexandru Gagniuc9ad52fe2014-01-27 20:57:54 -0600171 enum ELzmaStatus status;
Stefan Reinaueraa3f7ba2013-03-28 16:51:45 -0700172
173 size_t destlen = out_sizemax;
174 size_t srclen = src_len - (LZMA_PROPS_SIZE + 8);
175
Alexandru Gagniuc91e9f272014-01-26 22:55:01 -0600176 int res = LzmaDecode((uint8_t *) dst, &destlen,
177 (uint8_t *) &src[LZMA_PROPS_SIZE + 8], &srclen,
178 (uint8_t *) &src[0], LZMA_PROPS_SIZE,
Stefan Reinaueraa3f7ba2013-03-28 16:51:45 -0700179 LZMA_FINISH_END,
180 &status,
181 &LZMAalloc);
182
183 if (res != SZ_OK) {
184 ERROR("Error while decompressing.\n");
Gabe Blackdbd006b2014-02-20 23:38:49 -0800185 return -1;
Stefan Reinaueraa3f7ba2013-03-28 16:51:45 -0700186 }
Gabe Blackdbd006b2014-02-20 23:38:49 -0800187
Aaron Durbin5213c532015-10-23 17:38:40 -0500188 if (actual_size != NULL)
189 *actual_size = destlen;
190
Gabe Blackdbd006b2014-02-20 23:38:49 -0800191 return 0;
Stefan Reinaueraa3f7ba2013-03-28 16:51:45 -0700192}