drop svn:externals in the tree and add it locally.
[coreboot.git] / payloads / bayou / util / pbuilder / lzma / minilzma.cc
diff --git a/payloads/bayou/util/pbuilder/lzma/minilzma.cc b/payloads/bayou/util/pbuilder/lzma/minilzma.cc
new file mode 100644 (file)
index 0000000..7610910
--- /dev/null
@@ -0,0 +1,318 @@
+/*
+ * 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
+