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 
SzBigAlloc(void *,size_t size)15 static void *SzBigAlloc(void *, size_t size) { return BigAlloc(size); }
SzBigFree(void *,void * address)16 static void SzBigFree(void *, void *address) { BigFree(address); }
17 static ISzAlloc g_BigAlloc = { SzBigAlloc, SzBigFree };
18 
SzAlloc(void *,size_t size)19 static void *SzAlloc(void *, size_t size) { return MyAlloc(size); }
SzFree(void *,void * address)20 static void SzFree(void *, void *address) { MyFree(address); }
21 static ISzAlloc g_Alloc = { SzAlloc, SzFree };
22 
CEncoder()23 CEncoder::CEncoder()
24 {
25   _encoder = 0;
26   _encoder = LzmaEnc_Create(&g_Alloc);
27   if (_encoder == 0)
28     throw 1;
29 }
30 
~CEncoder()31 CEncoder::~CEncoder()
32 {
33   if (_encoder != 0)
34     LzmaEnc_Destroy(_encoder, &g_Alloc, &g_BigAlloc);
35 }
36 
GetUpperChar(wchar_t c)37 inline wchar_t GetUpperChar(wchar_t c)
38 {
39   if (c >= 'a' && c <= 'z')
40     c -= 0x20;
41   return c;
42 }
43 
ParseMatchFinder(const wchar_t * s,int * btMode,int * numHashBytes)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 #define SET_PROP_32(_id_, _dest_) case NCoderPropID::_id_: ep._dest_ = v; break;
77 
SetLzmaProp(PROPID propID,const PROPVARIANT & prop,CLzmaEncProps & ep)78 HRESULT SetLzmaProp(PROPID propID, const PROPVARIANT &prop, CLzmaEncProps &ep)
79 {
80   if (propID == NCoderPropID::kMatchFinder)
81   {
82     if (prop.vt != VT_BSTR)
83       return E_INVALIDARG;
84     return ParseMatchFinder(prop.bstrVal, &ep.btMode, &ep.numHashBytes) ? S_OK : E_INVALIDARG;
85   }
86   if (propID > NCoderPropID::kReduceSize)
87     return S_OK;
88   if (propID == NCoderPropID::kReduceSize)
89   {
90     if (prop.vt == VT_UI8)
91       ep.reduceSize = prop.uhVal.QuadPart;
92     return S_OK;
93   }
94   if (prop.vt != VT_UI4)
95     return E_INVALIDARG;
96   UInt32 v = prop.ulVal;
97   switch (propID)
98   {
99     case NCoderPropID::kDefaultProp: if (v > 31) return E_INVALIDARG; ep.dictSize = (UInt32)1 << (unsigned)v; break;
100     SET_PROP_32(kLevel, level)
101     SET_PROP_32(kNumFastBytes, fb)
102     SET_PROP_32(kMatchFinderCycles, mc)
103     SET_PROP_32(kAlgorithm, algo)
104     SET_PROP_32(kDictionarySize, dictSize)
105     SET_PROP_32(kPosStateBits, pb)
106     SET_PROP_32(kLitPosBits, lp)
107     SET_PROP_32(kLitContextBits, lc)
108     SET_PROP_32(kNumThreads, numThreads)
109     default: return E_INVALIDARG;
110   }
111   return S_OK;
112 }
113 
SetCoderProperties(const PROPID * propIDs,const PROPVARIANT * coderProps,UInt32 numProps)114 STDMETHODIMP CEncoder::SetCoderProperties(const PROPID *propIDs,
115     const PROPVARIANT *coderProps, UInt32 numProps)
116 {
117   CLzmaEncProps props;
118   LzmaEncProps_Init(&props);
119 
120   for (UInt32 i = 0; i < numProps; i++)
121   {
122     const PROPVARIANT &prop = coderProps[i];
123     PROPID propID = propIDs[i];
124     switch (propID)
125     {
126       case NCoderPropID::kEndMarker:
127         if (prop.vt != VT_BOOL) return E_INVALIDARG; props.writeEndMark = (prop.boolVal != VARIANT_FALSE); break;
128       default:
129         RINOK(SetLzmaProp(propID, prop, props));
130     }
131   }
132   return SResToHRESULT(LzmaEnc_SetProps(_encoder, &props));
133 }
134 
WriteCoderProperties(ISequentialOutStream * outStream)135 STDMETHODIMP CEncoder::WriteCoderProperties(ISequentialOutStream *outStream)
136 {
137   Byte props[LZMA_PROPS_SIZE];
138   size_t size = LZMA_PROPS_SIZE;
139   RINOK(LzmaEnc_WriteProperties(_encoder, props, &size));
140   return WriteStream(outStream, props, size);
141 }
142 
Code(ISequentialInStream * inStream,ISequentialOutStream * outStream,const UInt64 *,const UInt64 *,ICompressProgressInfo * progress)143 STDMETHODIMP CEncoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
144     const UInt64 * /* inSize */, const UInt64 * /* outSize */, ICompressProgressInfo *progress)
145 {
146   CSeqInStreamWrap inWrap(inStream);
147   CSeqOutStreamWrap outWrap(outStream);
148   CCompressProgressWrap progressWrap(progress);
149 
150   SRes res = LzmaEnc_Encode(_encoder, &outWrap.p, &inWrap.p, progress ? &progressWrap.p : NULL, &g_Alloc, &g_BigAlloc);
151   _inputProcessed = inWrap.Processed;
152   if (res == SZ_ERROR_READ && inWrap.Res != S_OK)
153     return inWrap.Res;
154   if (res == SZ_ERROR_WRITE && outWrap.Res != S_OK)
155     return outWrap.Res;
156   if (res == SZ_ERROR_PROGRESS && progressWrap.Res != S_OK)
157     return progressWrap.Res;
158   return SResToHRESULT(res);
159 }
160 
161 }}
162