2 * minimal lzma implementation
4 * Copyright (C) 2002 Eric Biederman
5 * Copyright (C) 2005 Joel Yliluoma
6 * Copyright (C) 2007 coresystems GmbH
7 * (Adapted by Stefan Reinauer <stepan@coresystems.de> for coresystems GmbH)
8 * Copyright (C) 2007 Patrick Georgi <patrick@georgi-clan.de>
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA
25 #include "C/Common/MyInitGuid.h"
26 #include "C/7zip/Compress/LZMA/LZMAEncoder.h"
28 #include <sys/types.h>
41 const std::vector<unsigned char> LZMACompress
42 (const std::vector<unsigned char>& buf);
44 const std::vector<unsigned char> LZMADeCompress
45 (const std::vector<unsigned char>& buf);
47 static inline uint16_t R16(const void* p)
49 const unsigned char* data = (const unsigned char*)p;
50 return (data[0] << 0) | (data[1] << 8);
52 static inline uint32_t R32(const void* p)
54 const unsigned char* data = (const unsigned char*)p;
55 return R16(data) | (R16(data+2) << 16);
60 static inline uint64_t R64(const void* p)
62 const unsigned char* data = (const unsigned char*)p;
63 return (L R32(data)) | ((L R32(data+4)) << 32);
68 static UInt32 SelectDictionarySizeFor(unsigned datasize)
74 /* gnu c can optimize this switch statement into a fast binary
75 * search, but it cannot do so for the list of the if statements.
79 case 0 ... 512 : return 512;
80 case 513 ... 1024: return 2048;
81 case 1025 ... 4096: return 8192;
82 case 4097 ... 16384: return 32768;
83 case 16385 ... 65536: return 528288;
84 case 65537 ... 528288: return 1048576*4;
85 case 528289 ... 786432: return 1048576*16;
86 default: return 1048576*32;
89 if(datasize <= 512) return 512;
90 if(datasize <= 1024) return 1024;
91 if(datasize <= 4096) return 4096;
92 if(datasize <= 16384) return 32768;
93 if(datasize <= 65536) return 528288;
94 if(datasize <= 528288) return 1048576*4;
95 if(datasize <= 786432) reutrn 1048576*16;
102 class CInStreamRam: public ISequentialInStream, public CMyUnknownImp
104 const std::vector<unsigned char>& input;
109 CInStreamRam(const std::vector<unsigned char>& buf) : input(buf), Pos(0)
112 virtual ~CInStreamRam() {}
114 STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
117 STDMETHODIMP CInStreamRam::Read(void *data, UInt32 size, UInt32 *processedSize)
119 UInt32 remain = input.size() - Pos;
120 if (size > remain) size = remain;
122 std::memcpy(data, &input[Pos], size);
125 if(processedSize != NULL) *processedSize = size;
130 class COutStreamRam: public ISequentialOutStream, public CMyUnknownImp
132 std::vector<Byte> result;
137 COutStreamRam(): result(), Pos(0) { }
138 virtual ~COutStreamRam() { }
140 void Reserve(unsigned n) { result.reserve(n); }
141 const std::vector<Byte>& Get() const { return result; }
143 HRESULT WriteByte(Byte b)
145 if(Pos >= result.size()) result.resize(Pos+1);
150 STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
153 STDMETHODIMP COutStreamRam::Write(const void *data, UInt32 size, UInt32 *processedSize)
155 if(Pos+size > result.size()) result.resize(Pos+size);
157 std::memcpy(&result[Pos], data, size);
158 if(processedSize != NULL) *processedSize = size;
163 const std::vector<unsigned char> LZMACompress(const std::vector<unsigned char>& buf)
165 if(buf.empty()) return buf;
167 const UInt32 dictionarysize = SelectDictionarySizeFor(buf.size());
169 NCompress::NLZMA::CEncoder *encoderSpec = new NCompress::NLZMA::CEncoder;
170 CMyComPtr<ICompressCoder> encoder = encoderSpec;
171 const PROPID propIDs[] =
173 NCoderPropID::kAlgorithm,
174 NCoderPropID::kDictionarySize,
175 NCoderPropID::kNumFastBytes,
177 const unsigned kNumProps = sizeof(propIDs) / sizeof(propIDs[0]);
178 PROPVARIANT properties[kNumProps];
179 properties[0].vt = VT_UI4; properties[0].ulVal = (UInt32)2;
180 properties[1].vt = VT_UI4; properties[1].ulVal = (UInt32)dictionarysize;
181 properties[2].vt = VT_UI4; properties[2].ulVal = (UInt32)64;
183 if (encoderSpec->SetCoderProperties(propIDs, properties, kNumProps) != S_OK)
186 return std::vector<unsigned char> ();
189 COutStreamRam *const outStreamSpec = new COutStreamRam;
190 CMyComPtr<ISequentialOutStream> outStream = outStreamSpec;
191 CInStreamRam *const inStreamSpec = new CInStreamRam(buf);
192 CMyComPtr<ISequentialInStream> inStream = inStreamSpec;
194 outStreamSpec->Reserve(buf.size());
196 if (encoderSpec->WriteCoderProperties(outStream) != S_OK) goto Error;
198 for (unsigned i = 0; i < 8; i++)
200 UInt64 t = (UInt64)buf.size();
201 outStreamSpec->WriteByte((Byte)((t) >> (8 * i)));
204 HRESULT lzmaResult = encoder->Code(inStream, outStream, 0, 0, 0);
205 if (lzmaResult != S_OK) goto Error;
207 return outStreamSpec->Get();
212 #include "C/7zip/Decompress/LzmaDecode.h"
213 #include "C/7zip/Decompress/LzmaDecode.c"
215 const std::vector<unsigned char> LZMADeCompress
216 (const std::vector<unsigned char>& buf)
218 if(buf.size() <= 5+8) return std::vector<unsigned char> ();
220 uint_least64_t out_sizemax = R64(&buf[5]);
222 std::vector<unsigned char> result(out_sizemax);
224 CLzmaDecoderState state;
225 LzmaDecodeProperties(&state.Properties, &buf[0], LZMA_PROPERTIES_SIZE);
226 state.Probs = new CProb[LzmaGetNumProbs(&state.Properties)];
230 LzmaDecode(&state, &buf[13], buf.size()-13, &in_done,
231 &result[0], result.size(), &out_done);
233 delete[] state.Probs;
235 result.resize(out_done);
240 int main(int argc, char *argv[])
243 FILE *f, *infile, *outfile;
247 std::fprintf(stderr, "'lzma e file1 file2' encodes file1 into file2.\n"
248 "'lzma d file2 file1' decodes file2 into file1.\n");
253 if ((s = argv[1], s[1] || strpbrk(s, "DEde") == NULL)
254 || (s = argv[2], (infile = fopen(s, "rb")) == NULL)
255 || (s = argv[3], (outfile = fopen(s, "wb")) == NULL)) {
256 std::fprintf(stderr, "??? %s\n", s);
263 if (fstat(fileno(infile), &fs)) {
264 std::perror(strerror(errno));
269 char *Buf=(char *)malloc(si);
270 fread(Buf,si, 1, infile);
272 std::vector<unsigned char> result;
273 if (toupper(*argv[1]) == 'E')
274 result = LZMACompress(std::vector<unsigned char>(Buf,Buf+si));
276 result = LZMADeCompress(std::vector<unsigned char>(Buf,Buf+si));
278 fwrite(&result[0], result.size(), 1, outfile);
287 * Compress a buffer with lzma
288 * Don't copy the result back if it is too large.
289 * @param in a pointer to the buffer
290 * @param in_len the length in bytes
291 * @param out a pointer to a buffer of at least size in_len
292 * @param out_len a pointer to the compressed length of in
295 void do_lzma_compress(char *in, int in_len, char *out, int *out_len) {
296 std::vector<unsigned char> result;
297 result = LZMACompress(std::vector<unsigned char>(in, in + in_len));
298 *out_len = result.size();
299 if (*out_len < in_len)
300 std::memcpy(out, &result[0], *out_len);
303 void do_lzma_uncompress(char *dst, int dst_len, char *src, int src_len) {
304 std::vector<unsigned char> result;
305 result = LZMADeCompress(std::vector<unsigned char>(src, src + src_len));
306 if (result.size() <= (SizeT)dst_len)
307 std::memcpy(dst, &result[0], result.size());
310 fprintf(stderr, "Not copying %d bytes to %d-byte buffer!\n",
311 (unsigned int)result.size(), dst_len);