1 // XzEncoder.cpp
2 
3 #include "StdAfx.h"
4 
5 #include "../../../C/Alloc.h"
6 
7 #include "../../Common/MyString.h"
8 #include "../../Common/StringToInt.h"
9 
10 #include "../Common/CWrappers.h"
11 #include "../Common/StreamUtils.h"
12 
13 #include "XzEncoder.h"
14 
15 namespace NCompress {
16 
17 namespace NLzma2 {
18 
19 HRESULT SetLzma2Prop(PROPID propID, const PROPVARIANT &prop, CLzma2EncProps &lzma2Props);
20 
21 }
22 
23 namespace NXz {
24 
InitCoderProps()25 void CEncoder::InitCoderProps()
26 {
27   XzProps_Init(&xzProps);
28 }
29 
CEncoder()30 CEncoder::CEncoder()
31 {
32   XzProps_Init(&xzProps);
33   _encoder = NULL;
34   _encoder = XzEnc_Create(&g_Alloc, &g_BigAlloc);
35   if (!_encoder)
36     throw 1;
37 }
38 
~CEncoder()39 CEncoder::~CEncoder()
40 {
41   if (_encoder)
42     XzEnc_Destroy(_encoder);
43 }
44 
45 
46 struct CMethodNamePair
47 {
48   UInt32 Id;
49   const char *Name;
50 };
51 
52 static const CMethodNamePair g_NamePairs[] =
53 {
54   { XZ_ID_Delta, "Delta" },
55   { XZ_ID_X86, "BCJ" },
56   { XZ_ID_PPC, "PPC" },
57   { XZ_ID_IA64, "IA64" },
58   { XZ_ID_ARM, "ARM" },
59   { XZ_ID_ARMT, "ARMT" },
60   { XZ_ID_SPARC, "SPARC" }
61   // { XZ_ID_LZMA2, "LZMA2" }
62 };
63 
FilterIdFromName(const wchar_t * name)64 static int FilterIdFromName(const wchar_t *name)
65 {
66   for (unsigned i = 0; i < ARRAY_SIZE(g_NamePairs); i++)
67   {
68     const CMethodNamePair &pair = g_NamePairs[i];
69     if (StringsAreEqualNoCase_Ascii(name, pair.Name))
70       return (int)pair.Id;
71   }
72   return -1;
73 }
74 
75 
SetCheckSize(UInt32 checkSizeInBytes)76 HRESULT CEncoder::SetCheckSize(UInt32 checkSizeInBytes)
77 {
78   unsigned id;
79   switch (checkSizeInBytes)
80   {
81     case  0: id = XZ_CHECK_NO; break;
82     case  4: id = XZ_CHECK_CRC32; break;
83     case  8: id = XZ_CHECK_CRC64; break;
84     case 32: id = XZ_CHECK_SHA256; break;
85     default: return E_INVALIDARG;
86   }
87   xzProps.checkId = id;
88   return S_OK;
89 }
90 
91 
SetCoderProp(PROPID propID,const PROPVARIANT & prop)92 HRESULT CEncoder::SetCoderProp(PROPID propID, const PROPVARIANT &prop)
93 {
94   if (propID == NCoderPropID::kNumThreads)
95   {
96     if (prop.vt != VT_UI4)
97       return E_INVALIDARG;
98     xzProps.numTotalThreads = (int)(prop.ulVal);
99     return S_OK;
100   }
101 
102   if (propID == NCoderPropID::kCheckSize)
103   {
104     if (prop.vt != VT_UI4)
105       return E_INVALIDARG;
106     return SetCheckSize(prop.ulVal);
107   }
108 
109   if (propID == NCoderPropID::kBlockSize2)
110   {
111     if (prop.vt == VT_UI4)
112       xzProps.blockSize = prop.ulVal;
113     else if (prop.vt == VT_UI8)
114       xzProps.blockSize = prop.uhVal.QuadPart;
115     else
116       return E_INVALIDARG;
117     return S_OK;
118   }
119 
120   if (propID == NCoderPropID::kReduceSize)
121   {
122     if (prop.vt == VT_UI8)
123       xzProps.reduceSize = prop.uhVal.QuadPart;
124     else
125       return E_INVALIDARG;
126     return S_OK;
127   }
128 
129   if (propID == NCoderPropID::kFilter)
130   {
131     if (prop.vt == VT_UI4)
132     {
133       UInt32 id32 = prop.ulVal;
134       if (id32 == XZ_ID_Delta)
135         return E_INVALIDARG;
136       xzProps.filterProps.id = prop.ulVal;
137     }
138     else
139     {
140       if (prop.vt != VT_BSTR)
141         return E_INVALIDARG;
142 
143       const wchar_t *name = prop.bstrVal;
144       const wchar_t *end;
145 
146       UInt32 id32 = ConvertStringToUInt32(name, &end);
147 
148       if (end != name)
149         name = end;
150       else
151       {
152         if (IsString1PrefixedByString2_NoCase_Ascii(name, "Delta"))
153         {
154           name += 5; // strlen("Delta");
155           id32 = XZ_ID_Delta;
156         }
157         else
158         {
159           int filterId = FilterIdFromName(prop.bstrVal);
160           if (filterId < 0 /* || filterId == XZ_ID_LZMA2 */)
161             return E_INVALIDARG;
162           id32 = filterId;
163         }
164       }
165 
166       if (id32 == XZ_ID_Delta)
167       {
168         wchar_t c = *name;
169         if (c != '-' && c != ':')
170           return E_INVALIDARG;
171         name++;
172         UInt32 delta = ConvertStringToUInt32(name, &end);
173         if (end == name || *end != 0 || delta == 0 || delta > 256)
174           return E_INVALIDARG;
175         xzProps.filterProps.delta = delta;
176       }
177 
178       xzProps.filterProps.id = id32;
179     }
180 
181     return S_OK;
182   }
183 
184   return NLzma2::SetLzma2Prop(propID, prop, xzProps.lzma2Props);
185 }
186 
187 
SetCoderProperties(const PROPID * propIDs,const PROPVARIANT * coderProps,UInt32 numProps)188 STDMETHODIMP CEncoder::SetCoderProperties(const PROPID *propIDs,
189     const PROPVARIANT *coderProps, UInt32 numProps)
190 {
191   XzProps_Init(&xzProps);
192 
193   for (UInt32 i = 0; i < numProps; i++)
194   {
195     RINOK(SetCoderProp(propIDs[i], coderProps[i]));
196   }
197 
198   return S_OK;
199   // return SResToHRESULT(XzEnc_SetProps(_encoder, &xzProps));
200 }
201 
202 
SetCoderPropertiesOpt(const PROPID * propIDs,const PROPVARIANT * coderProps,UInt32 numProps)203 STDMETHODIMP CEncoder::SetCoderPropertiesOpt(const PROPID *propIDs,
204     const PROPVARIANT *coderProps, UInt32 numProps)
205 {
206   for (UInt32 i = 0; i < numProps; i++)
207   {
208     const PROPVARIANT &prop = coderProps[i];
209     PROPID propID = propIDs[i];
210     if (propID == NCoderPropID::kExpectedDataSize)
211       if (prop.vt == VT_UI8)
212         XzEnc_SetDataSize(_encoder, prop.uhVal.QuadPart);
213   }
214   return S_OK;
215 }
216 
217 
218 #define RET_IF_WRAP_ERROR(wrapRes, sRes, sResErrorCode) \
219   if (wrapRes != S_OK /* && (sRes == SZ_OK || sRes == sResErrorCode) */) return wrapRes;
220 
Code(ISequentialInStream * inStream,ISequentialOutStream * outStream,const UInt64 *,const UInt64 *,ICompressProgressInfo * progress)221 STDMETHODIMP CEncoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
222     const UInt64 * /* inSize */, const UInt64 * /* outSize */, ICompressProgressInfo *progress)
223 {
224   CSeqInStreamWrap inWrap;
225   CSeqOutStreamWrap outWrap;
226   CCompressProgressWrap progressWrap;
227 
228   inWrap.Init(inStream);
229   outWrap.Init(outStream);
230   progressWrap.Init(progress);
231 
232   SRes res = XzEnc_SetProps(_encoder, &xzProps);
233   if (res == SZ_OK)
234     res = XzEnc_Encode(_encoder, &outWrap.vt, &inWrap.vt, progress ? &progressWrap.vt : NULL);
235 
236   // SRes res = Xz_Encode(&outWrap.vt, &inWrap.vt, &xzProps, progress ? &progressWrap.vt : NULL);
237 
238   RET_IF_WRAP_ERROR(inWrap.Res, res, SZ_ERROR_READ)
239   RET_IF_WRAP_ERROR(outWrap.Res, res, SZ_ERROR_WRITE)
240   RET_IF_WRAP_ERROR(progressWrap.Res, res, SZ_ERROR_PROGRESS)
241 
242   return SResToHRESULT(res);
243 }
244 
245 }}
246