| /* |
| * minimal lzma implementation |
| * |
| * Copyright (C) 2002 Eric Biederman |
| * Copyright (C) 2005 Joel Yliluoma |
| * Copyright (C) 2007 coresystems GmbH |
| * (Adapted by Stefan Reinauer <stepan@coresystems.de> for coresystems GmbH) |
| * Copyright (C) 2007 Patrick Georgi <patrick@georgi-clan.de> |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License as published by |
| * the Free Software Foundation; either version 2 of the License, or |
| * (at your option) any later version. |
| * |
| * This program is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| * GNU General Public License for more details. |
| * |
| * You should have received a copy of the GNU General Public License |
| * along with this program; if not, write to the Free Software |
| * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA |
| */ |
| |
| #include "C/Common/MyInitGuid.h" |
| #include "C/7zip/Compress/LZMA/LZMAEncoder.h" |
| |
| #include <sys/types.h> |
| #include <sys/stat.h> |
| #include <unistd.h> |
| #include <errno.h> |
| #include <cstring> |
| #include <cstdio> |
| #include <cstdlib> |
| #include <cctype> |
| |
| #include <vector> |
| #include <algorithm> |
| #include <stdint.h> |
| |
| const std::vector<unsigned char> LZMACompress |
| (const std::vector<unsigned char>& buf); |
| |
| const std::vector<unsigned char> LZMADeCompress |
| (const std::vector<unsigned char>& buf); |
| |
| static inline uint16_t R16(const void* p) |
| { |
| const unsigned char* data = (const unsigned char*)p; |
| return (data[0] << 0) | (data[1] << 8); |
| } |
| static inline uint32_t R32(const void* p) |
| { |
| const unsigned char* data = (const unsigned char*)p; |
| return R16(data) | (R16(data+2) << 16); |
| } |
| |
| #define L (uint64_t) |
| |
| static inline uint64_t R64(const void* p) |
| { |
| const unsigned char* data = (const unsigned char*)p; |
| return (L R32(data)) | ((L R32(data+4)) << 32); |
| } |
| |
| #undef L |
| |
| static UInt32 SelectDictionarySizeFor(unsigned datasize) |
| { |
| #if 1 |
| return datasize; |
| #else |
| #ifdef __GNUC__ |
| /* gnu c can optimize this switch statement into a fast binary |
| * search, but it cannot do so for the list of the if statements. |
| */ |
| switch(datasize) |
| { |
| case 0 ... 512 : return 512; |
| case 513 ... 1024: return 2048; |
| case 1025 ... 4096: return 8192; |
| case 4097 ... 16384: return 32768; |
| case 16385 ... 65536: return 528288; |
| case 65537 ... 528288: return 1048576*4; |
| case 528289 ... 786432: return 1048576*16; |
| default: return 1048576*32; |
| } |
| #else |
| if(datasize <= 512) return 512; |
| if(datasize <= 1024) return 1024; |
| if(datasize <= 4096) return 4096; |
| if(datasize <= 16384) return 32768; |
| if(datasize <= 65536) return 528288; |
| if(datasize <= 528288) return 1048576*4; |
| if(datasize <= 786432) reutrn 1048576*16; |
| return 32*1048576; |
| #endif |
| #endif |
| } |
| |
| |
| class CInStreamRam: public ISequentialInStream, public CMyUnknownImp |
| { |
| const std::vector<unsigned char>& input; |
| size_t Pos; |
| public: |
| MY_UNKNOWN_IMP |
| |
| CInStreamRam(const std::vector<unsigned char>& buf) : input(buf), Pos(0) |
| { |
| } |
| virtual ~CInStreamRam() {} |
| |
| STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); |
| }; |
| |
| STDMETHODIMP CInStreamRam::Read(void *data, UInt32 size, UInt32 *processedSize) |
| { |
| UInt32 remain = input.size() - Pos; |
| if (size > remain) size = remain; |
| |
| std::memcpy(data, &input[Pos], size); |
| Pos += size; |
| |
| if(processedSize != NULL) *processedSize = size; |
| |
| return S_OK; |
| } |
| |
| class COutStreamRam: public ISequentialOutStream, public CMyUnknownImp |
| { |
| std::vector<Byte> result; |
| size_t Pos; |
| public: |
| MY_UNKNOWN_IMP |
| |
| COutStreamRam(): result(), Pos(0) { } |
| virtual ~COutStreamRam() { } |
| |
| void Reserve(unsigned n) { result.reserve(n); } |
| const std::vector<Byte>& Get() const { return result; } |
| |
| HRESULT WriteByte(Byte b) |
| { |
| if(Pos >= result.size()) result.resize(Pos+1); |
| result[Pos++] = b; |
| return S_OK; |
| } |
| |
| STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize); |
| }; |
| |
| STDMETHODIMP COutStreamRam::Write(const void *data, UInt32 size, UInt32 *processedSize) |
| { |
| if(Pos+size > result.size()) result.resize(Pos+size); |
| |
| std::memcpy(&result[Pos], data, size); |
| if(processedSize != NULL) *processedSize = size; |
| Pos += size; |
| return S_OK; |
| } |
| |
| const std::vector<unsigned char> LZMACompress(const std::vector<unsigned char>& buf) |
| { |
| if(buf.empty()) return buf; |
| |
| const UInt32 dictionarysize = SelectDictionarySizeFor(buf.size()); |
| |
| NCompress::NLZMA::CEncoder *encoderSpec = new NCompress::NLZMA::CEncoder; |
| CMyComPtr<ICompressCoder> encoder = encoderSpec; |
| const PROPID propIDs[] = |
| { |
| NCoderPropID::kAlgorithm, |
| NCoderPropID::kDictionarySize, |
| NCoderPropID::kNumFastBytes, |
| }; |
| const unsigned kNumProps = sizeof(propIDs) / sizeof(propIDs[0]); |
| PROPVARIANT properties[kNumProps]; |
| properties[0].vt = VT_UI4; properties[0].ulVal = (UInt32)2; |
| properties[1].vt = VT_UI4; properties[1].ulVal = (UInt32)dictionarysize; |
| properties[2].vt = VT_UI4; properties[2].ulVal = (UInt32)64; |
| |
| if (encoderSpec->SetCoderProperties(propIDs, properties, kNumProps) != S_OK) |
| { |
| Error: |
| return std::vector<unsigned char> (); |
| } |
| |
| COutStreamRam *const outStreamSpec = new COutStreamRam; |
| CMyComPtr<ISequentialOutStream> outStream = outStreamSpec; |
| CInStreamRam *const inStreamSpec = new CInStreamRam(buf); |
| CMyComPtr<ISequentialInStream> inStream = inStreamSpec; |
| |
| outStreamSpec->Reserve(buf.size()); |
| |
| if (encoderSpec->WriteCoderProperties(outStream) != S_OK) goto Error; |
| |
| for (unsigned i = 0; i < 8; i++) |
| { |
| UInt64 t = (UInt64)buf.size(); |
| outStreamSpec->WriteByte((Byte)((t) >> (8 * i))); |
| } |
| |
| HRESULT lzmaResult = encoder->Code(inStream, outStream, 0, 0, 0); |
| if (lzmaResult != S_OK) goto Error; |
| |
| return outStreamSpec->Get(); |
| } |
| |
| #undef RC_NORMALIZE |
| |
| #include "C/7zip/Decompress/LzmaDecode.h" |
| #include "C/7zip/Decompress/LzmaDecode.c" |
| |
| const std::vector<unsigned char> LZMADeCompress |
| (const std::vector<unsigned char>& buf) |
| { |
| if(buf.size() <= 5+8) return std::vector<unsigned char> (); |
| |
| uint_least64_t out_sizemax = R64(&buf[5]); |
| |
| std::vector<unsigned char> result(out_sizemax); |
| |
| CLzmaDecoderState state; |
| LzmaDecodeProperties(&state.Properties, &buf[0], LZMA_PROPERTIES_SIZE); |
| state.Probs = new CProb[LzmaGetNumProbs(&state.Properties)]; |
| |
| SizeT in_done; |
| SizeT out_done; |
| LzmaDecode(&state, &buf[13], buf.size()-13, &in_done, |
| &result[0], result.size(), &out_done); |
| |
| delete[] state.Probs; |
| |
| result.resize(out_done); |
| return result; |
| } |
| |
| #ifndef COMPACT |
| int main(int argc, char *argv[]) |
| { |
| char *s; |
| FILE *f, *infile, *outfile; |
| int c; |
| |
| if (argc != 4) { |
| std::fprintf(stderr, "'lzma e file1 file2' encodes file1 into file2.\n" |
| "'lzma d file2 file1' decodes file2 into file1.\n"); |
| |
| return EXIT_FAILURE; |
| } |
| if (argc == 4) { |
| if ((s = argv[1], s[1] || strpbrk(s, "DEde") == NULL) |
| || (s = argv[2], (infile = fopen(s, "rb")) == NULL) |
| || (s = argv[3], (outfile = fopen(s, "wb")) == NULL)) { |
| std::fprintf(stderr, "??? %s\n", s); |
| return EXIT_FAILURE; |
| } |
| } |
| |
| struct stat fs; |
| int si; |
| if (fstat(fileno(infile), &fs)) { |
| std::perror(strerror(errno)); |
| return EXIT_FAILURE; |
| } |
| si=fs.st_size; |
| |
| char *Buf=(char *)malloc(si); |
| fread(Buf,si, 1, infile); |
| |
| std::vector<unsigned char> result; |
| if (toupper(*argv[1]) == 'E') |
| result = LZMACompress(std::vector<unsigned char>(Buf,Buf+si)); |
| else |
| result = LZMADeCompress(std::vector<unsigned char>(Buf,Buf+si)); |
| |
| fwrite(&result[0], result.size(), 1, outfile); |
| fclose(infile); |
| fclose(outfile); |
| return EXIT_SUCCESS; |
| } |
| #else |
| extern "C" { |
| |
| /** |
| * Compress a buffer with lzma |
| * Don't copy the result back if it is too large. |
| * @param in a pointer to the buffer |
| * @param in_len the length in bytes |
| * @param out a pointer to a buffer of at least size in_len |
| * @param out_len a pointer to the compressed length of in |
| */ |
| |
| void do_lzma_compress(char *in, int in_len, char *out, int *out_len) { |
| std::vector<unsigned char> result; |
| result = LZMACompress(std::vector<unsigned char>(in, in + in_len)); |
| *out_len = result.size(); |
| if (*out_len < in_len) |
| std::memcpy(out, &result[0], *out_len); |
| } |
| |
| void do_lzma_uncompress(char *dst, int dst_len, char *src, int src_len) { |
| std::vector<unsigned char> result; |
| result = LZMADeCompress(std::vector<unsigned char>(src, src + src_len)); |
| if (result.size() <= dst_len) |
| std::memcpy(dst, &result[0], result.size()); |
| else |
| { |
| fprintf(stderr, "Not copying %d bytes to %d-byte buffer!\n", |
| result.size(), dst_len); |
| exit(1); |
| } |
| } |
| |
| } |
| #endif |
| |