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