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