• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
CEncoder()15 CEncoder::CEncoder()
16 {
17   _encoder = NULL;
18   _encoder = LzmaEnc_Create(&g_AlignedAlloc);
19   if (!_encoder)
20     throw 1;
21 }
22 
~CEncoder()23 CEncoder::~CEncoder()
24 {
25   if (_encoder)
26     LzmaEnc_Destroy(_encoder, &g_AlignedAlloc, &g_BigAlloc);
27 }
28 
GetUpperChar(wchar_t c)29 static inline wchar_t GetUpperChar(wchar_t c)
30 {
31   if (c >= 'a' && c <= 'z')
32     c -= 0x20;
33   return c;
34 }
35 
ParseMatchFinder(const wchar_t * s,int * btMode,int * numHashBytes)36 static int ParseMatchFinder(const wchar_t *s, int *btMode, int *numHashBytes)
37 {
38   wchar_t c = GetUpperChar(*s++);
39   if (c == L'H')
40   {
41     if (GetUpperChar(*s++) != L'C')
42       return 0;
43     int numHashBytesLoc = (int)(*s++ - L'0');
44     if (numHashBytesLoc < 4 || numHashBytesLoc > 4)
45       return 0;
46     if (*s != 0)
47       return 0;
48     *btMode = 0;
49     *numHashBytes = numHashBytesLoc;
50     return 1;
51   }
52 
53   if (c != L'B')
54     return 0;
55   if (GetUpperChar(*s++) != L'T')
56     return 0;
57   int numHashBytesLoc = (int)(*s++ - L'0');
58   if (numHashBytesLoc < 2 || numHashBytesLoc > 4)
59     return 0;
60   if (*s != 0)
61     return 0;
62   *btMode = 1;
63   *numHashBytes = numHashBytesLoc;
64   return 1;
65 }
66 
67 #define SET_PROP_32(_id_, _dest_) case NCoderPropID::_id_: ep._dest_ = v; break;
68 
SetLzmaProp(PROPID propID,const PROPVARIANT & prop,CLzmaEncProps & ep)69 HRESULT SetLzmaProp(PROPID propID, const PROPVARIANT &prop, CLzmaEncProps &ep)
70 {
71   if (propID == NCoderPropID::kMatchFinder)
72   {
73     if (prop.vt != VT_BSTR)
74       return E_INVALIDARG;
75     return ParseMatchFinder(prop.bstrVal, &ep.btMode, &ep.numHashBytes) ? S_OK : E_INVALIDARG;
76   }
77 
78   if (propID > NCoderPropID::kReduceSize)
79     return S_OK;
80 
81   if (propID == NCoderPropID::kReduceSize)
82   {
83     if (prop.vt == VT_UI8)
84       ep.reduceSize = prop.uhVal.QuadPart;
85     else
86       return E_INVALIDARG;
87     return S_OK;
88   }
89 
90   if (prop.vt != VT_UI4)
91     return E_INVALIDARG;
92   UInt32 v = prop.ulVal;
93   switch (propID)
94   {
95     case NCoderPropID::kDefaultProp: if (v > 31) return E_INVALIDARG; ep.dictSize = (UInt32)1 << (unsigned)v; break;
96     SET_PROP_32(kLevel, level)
97     SET_PROP_32(kNumFastBytes, fb)
98     SET_PROP_32(kMatchFinderCycles, mc)
99     SET_PROP_32(kAlgorithm, algo)
100     SET_PROP_32(kDictionarySize, dictSize)
101     SET_PROP_32(kPosStateBits, pb)
102     SET_PROP_32(kLitPosBits, lp)
103     SET_PROP_32(kLitContextBits, lc)
104     SET_PROP_32(kNumThreads, numThreads)
105     default: return E_INVALIDARG;
106   }
107   return S_OK;
108 }
109 
SetCoderProperties(const PROPID * propIDs,const PROPVARIANT * coderProps,UInt32 numProps)110 STDMETHODIMP CEncoder::SetCoderProperties(const PROPID *propIDs,
111     const PROPVARIANT *coderProps, UInt32 numProps)
112 {
113   CLzmaEncProps props;
114   LzmaEncProps_Init(&props);
115 
116   for (UInt32 i = 0; i < numProps; i++)
117   {
118     const PROPVARIANT &prop = coderProps[i];
119     PROPID propID = propIDs[i];
120     switch (propID)
121     {
122       case NCoderPropID::kEndMarker:
123         if (prop.vt != VT_BOOL) return E_INVALIDARG; props.writeEndMark = (prop.boolVal != VARIANT_FALSE); break;
124       default:
125         RINOK(SetLzmaProp(propID, prop, props));
126     }
127   }
128   return SResToHRESULT(LzmaEnc_SetProps(_encoder, &props));
129 }
130 
131 
SetCoderPropertiesOpt(const PROPID * propIDs,const PROPVARIANT * coderProps,UInt32 numProps)132 STDMETHODIMP CEncoder::SetCoderPropertiesOpt(const PROPID *propIDs,
133     const PROPVARIANT *coderProps, UInt32 numProps)
134 {
135   for (UInt32 i = 0; i < numProps; i++)
136   {
137     const PROPVARIANT &prop = coderProps[i];
138     PROPID propID = propIDs[i];
139     if (propID == NCoderPropID::kExpectedDataSize)
140       if (prop.vt == VT_UI8)
141         LzmaEnc_SetDataSize(_encoder, prop.uhVal.QuadPart);
142   }
143   return S_OK;
144 }
145 
146 
WriteCoderProperties(ISequentialOutStream * outStream)147 STDMETHODIMP CEncoder::WriteCoderProperties(ISequentialOutStream *outStream)
148 {
149   Byte props[LZMA_PROPS_SIZE];
150   size_t size = LZMA_PROPS_SIZE;
151   RINOK(LzmaEnc_WriteProperties(_encoder, props, &size));
152   return WriteStream(outStream, props, size);
153 }
154 
155 
156 #define RET_IF_WRAP_ERROR(wrapRes, sRes, sResErrorCode) \
157   if (wrapRes != S_OK /* && (sRes == SZ_OK || sRes == sResErrorCode) */) return wrapRes;
158 
Code(ISequentialInStream * inStream,ISequentialOutStream * outStream,const UInt64 *,const UInt64 *,ICompressProgressInfo * progress)159 STDMETHODIMP CEncoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
160     const UInt64 * /* inSize */, const UInt64 * /* outSize */, ICompressProgressInfo *progress)
161 {
162   CSeqInStreamWrap inWrap;
163   CSeqOutStreamWrap outWrap;
164   CCompressProgressWrap progressWrap;
165 
166   inWrap.Init(inStream);
167   outWrap.Init(outStream);
168   progressWrap.Init(progress);
169 
170   SRes res = LzmaEnc_Encode(_encoder, &outWrap.vt, &inWrap.vt,
171       progress ? &progressWrap.vt : NULL, &g_AlignedAlloc, &g_BigAlloc);
172 
173   _inputProcessed = inWrap.Processed;
174 
175   RET_IF_WRAP_ERROR(inWrap.Res, res, SZ_ERROR_READ)
176   RET_IF_WRAP_ERROR(outWrap.Res, res, SZ_ERROR_WRITE)
177   RET_IF_WRAP_ERROR(progressWrap.Res, res, SZ_ERROR_PROGRESS)
178 
179   return SResToHRESULT(res);
180 }
181 
182 }}
183