Home | History | Annotate | Download | only in Compress
      1 // LzmaEncoder.cpp
      2 
      3 #include "StdAfx.h"
      4 
      5 #include "../../../C/Alloc.h"
      6 
      7 #include "../Common/CWrappers.h"
      8 #include "../Common/StreamUtils.h"
      9 
     10 #include "LzmaEncoder.h"
     11 
     12 namespace NCompress {
     13 namespace NLzma {
     14 
     15 static void *SzBigAlloc(void *, size_t size) { return BigAlloc(size); }
     16 static void SzBigFree(void *, void *address) { BigFree(address); }
     17 static ISzAlloc g_BigAlloc = { SzBigAlloc, SzBigFree };
     18 
     19 static void *SzAlloc(void *, size_t size) { return MyAlloc(size); }
     20 static void SzFree(void *, void *address) { MyFree(address); }
     21 static ISzAlloc g_Alloc = { SzAlloc, SzFree };
     22 
     23 CEncoder::CEncoder()
     24 {
     25   _encoder = 0;
     26   _encoder = LzmaEnc_Create(&g_Alloc);
     27   if (_encoder == 0)
     28     throw 1;
     29 }
     30 
     31 CEncoder::~CEncoder()
     32 {
     33   if (_encoder != 0)
     34     LzmaEnc_Destroy(_encoder, &g_Alloc, &g_BigAlloc);
     35 }
     36 
     37 inline wchar_t GetUpperChar(wchar_t c)
     38 {
     39   if (c >= 'a' && c <= 'z')
     40     c -= 0x20;
     41   return c;
     42 }
     43 
     44 static int ParseMatchFinder(const wchar_t *s, int *btMode, int *numHashBytes)
     45 {
     46   wchar_t c = GetUpperChar(*s++);
     47   if (c == L'H')
     48   {
     49     if (GetUpperChar(*s++) != L'C')
     50       return 0;
     51     int numHashBytesLoc = (int)(*s++ - L'0');
     52     if (numHashBytesLoc < 4 || numHashBytesLoc > 4)
     53       return 0;
     54     if (*s++ != 0)
     55       return 0;
     56     *btMode = 0;
     57     *numHashBytes = numHashBytesLoc;
     58     return 1;
     59   }
     60   if (c != L'B')
     61     return 0;
     62 
     63   if (GetUpperChar(*s++) != L'T')
     64     return 0;
     65   int numHashBytesLoc = (int)(*s++ - L'0');
     66   if (numHashBytesLoc < 2 || numHashBytesLoc > 4)
     67     return 0;
     68   c = GetUpperChar(*s++);
     69   if (c != L'\0')
     70     return 0;
     71   *btMode = 1;
     72   *numHashBytes = numHashBytesLoc;
     73   return 1;
     74 }
     75 
     76 HRESULT SetLzmaProp(PROPID propID, const PROPVARIANT &prop, CLzmaEncProps &ep)
     77 {
     78   if (propID == NCoderPropID::kMatchFinder)
     79   {
     80     if (prop.vt != VT_BSTR)
     81       return E_INVALIDARG;
     82     return ParseMatchFinder(prop.bstrVal, &ep.btMode, &ep.numHashBytes) ? S_OK : E_INVALIDARG;
     83   }
     84   if (prop.vt != VT_UI4)
     85     return E_INVALIDARG;
     86   UInt32 v = prop.ulVal;
     87   switch (propID)
     88   {
     89     case NCoderPropID::kNumFastBytes: ep.fb = v; break;
     90     case NCoderPropID::kMatchFinderCycles: ep.mc = v; break;
     91     case NCoderPropID::kAlgorithm: ep.algo = v; break;
     92     case NCoderPropID::kDictionarySize: ep.dictSize = v; break;
     93     case NCoderPropID::kPosStateBits: ep.pb = v; break;
     94     case NCoderPropID::kLitPosBits: ep.lp = v; break;
     95     case NCoderPropID::kLitContextBits: ep.lc = v; break;
     96     default: return E_INVALIDARG;
     97   }
     98   return S_OK;
     99 }
    100 
    101 STDMETHODIMP CEncoder::SetCoderProperties(const PROPID *propIDs,
    102     const PROPVARIANT *coderProps, UInt32 numProps)
    103 {
    104   CLzmaEncProps props;
    105   LzmaEncProps_Init(&props);
    106 
    107   for (UInt32 i = 0; i < numProps; i++)
    108   {
    109     const PROPVARIANT &prop = coderProps[i];
    110     PROPID propID = propIDs[i];
    111     switch (propID)
    112     {
    113       case NCoderPropID::kEndMarker:
    114         if (prop.vt != VT_BOOL) return E_INVALIDARG; props.writeEndMark = (prop.boolVal == VARIANT_TRUE); break;
    115       case NCoderPropID::kNumThreads:
    116         if (prop.vt != VT_UI4) return E_INVALIDARG; props.numThreads = prop.ulVal; break;
    117       default:
    118         RINOK(SetLzmaProp(propID, prop, props));
    119     }
    120   }
    121   return SResToHRESULT(LzmaEnc_SetProps(_encoder, &props));
    122 }
    123 
    124 STDMETHODIMP CEncoder::WriteCoderProperties(ISequentialOutStream *outStream)
    125 {
    126   Byte props[LZMA_PROPS_SIZE];
    127   size_t size = LZMA_PROPS_SIZE;
    128   RINOK(LzmaEnc_WriteProperties(_encoder, props, &size));
    129   return WriteStream(outStream, props, size);
    130 }
    131 
    132 STDMETHODIMP CEncoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
    133     const UInt64 * /* inSize */, const UInt64 * /* outSize */, ICompressProgressInfo *progress)
    134 {
    135   CSeqInStreamWrap inWrap(inStream);
    136   CSeqOutStreamWrap outWrap(outStream);
    137   CCompressProgressWrap progressWrap(progress);
    138 
    139   SRes res = LzmaEnc_Encode(_encoder, &outWrap.p, &inWrap.p, progress ? &progressWrap.p : NULL, &g_Alloc, &g_BigAlloc);
    140   if (res == SZ_ERROR_READ && inWrap.Res != S_OK)
    141     return inWrap.Res;
    142   if (res == SZ_ERROR_WRITE && outWrap.Res != S_OK)
    143     return outWrap.Res;
    144   if (res == SZ_ERROR_PROGRESS && progressWrap.Res != S_OK)
    145     return progressWrap.Res;
    146   return SResToHRESULT(res);
    147 }
    148 
    149 }}
    150